Reputation: 1535
I am having trouble constructing a query using SQLalchemy. Here is a simplified representation of the models I have defined:
Project
class Project(Base):
__tablename__ = 'project'
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False, unique=True)
# User associations
users = relationship(
'User',
secondary='user_project_association'
)
User
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False, unique=True)
# Project associations
projects = relationship(
'Project',
secondary='user_project_association'
)
User <-> Project (association)
class UserProjectAssociation(Base):
__tablename__ = 'user_project_association'
# User association.
user_id = Column(Integer, ForeignKey('user.id'), primary_key=True)
user = relationship('User', backref='project_associations')
# Project association.
project_id = Column(Integer, ForeignKey('project.id'), primary_key=True)
project = relationship('Project', backref='user_associations')
I want to perform a query on the projects table such that the result contains information about the projects as well as information about the associated users - if there are any. I am including a filter based on the user name. I am eventually going to send the result as JSON via a REST API so I would prefer the results as python {dict} objects rather than SQLAlchemy objects. The query I am performing looks like:
# Add return fields
query = session.query(
Project.id,
Project.name,
User.id.label('users.id'),
User.name.label('users.name')
)
# Add join statements
query = query.outerjoin(User, Project.users)
# Add filters
query = query.filter(
Project.name == 'proj1',
User.name != 'jane.doe' # <--- I think this is causing the issue.
)
# Execute
results = query.all()
data = [result._asdict() for result in results]
print(data)
The database contains a project called proj1 which doesn't have any associated users. In this particular scenario, I am filtering on a user column and the user association does not exist. However, I am still expecting to get a row for the project in my results but the query returns an empty list. The result I am expecting would look something like this:
[{'id': 1, 'name': 'proj1', 'users.id': None, 'users.name': None}]
Can someone explain where I am going wrong?
Upvotes: 1
Views: 1975
Reputation: 52929
You have to account for the NULL values that result from the left join, since !=
compares values and NULL is the absence of value, so the result of NULL != 'jane.doe'
is NULL, not true:
query = query.filter(
Project.name == 'proj1',
or_(User.name == None, User.name != 'jane.doe')
)
Note that SQLAlchemy handles equality with None in a special way and produces IS NULL
. If you want to be less ambiguous you could also use User.name.is_(None)
.
Upvotes: 4