Wrapping my head around a way to get a list of Jobs associated to a User. My DB Model goes a little something like this.
class Job(db.Model):
id = db.Column(db.Integer, primary_key=True)
# Relationship Rows
actions = db.relationship('JobAction', backref='job')
class JobAction(db.Model):
id = db.Column(db.Integer, primary_key=True)
# Linked Rows
user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
# Relationship Rows
user = db.relationship('User', foreign_keys=[user_id], backref='jobactions')
I need to get a list of Jobs that are associated to a User. I can use either the User already matching a logged in users details. Or the user.id.
I was looking at something like the below, but no dice. I can see it's overly optimistic a query, but can't see what's up. Potentially a missing Join.
# Get User first.
user = User.query.filter_by(id=1).first()
# Get their Jobs
jobs = Job.query.filter_by(actions.user=user).all()
Any ideas would be greatly appreciated.
Cheers,
I'm guessing you are missing a foreign key. If your database model looked like this:
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
jobactions = db.relationship("JobAction", back_populates="user")
class Job(db.Model):
__tablename__ = 'jobs'
id = db.Column(db.Integer, primary_key=True)
jobactions = db.relationship('JobAction', backref='job')
class JobAction(db.Model):
__tablename__ = 'jobactions'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
job_id = db.Column(db.Integer, db.ForeignKey('jobs.id'))
user = db.relationship(User, back_populates="jobactions")
job = db.relationship(Job, back_populates="jobactions")
Then you could use:
jobs = [ jobaction.job for jobaction in user.jobactions ]
Related
I am into a very confusing situation where I have one to many relation and I want to query data like I want all parent table data but want to get only data from child tables which fulfill condition of site_id = 100.
class Policy(Base):
"""table containing details for Policies"""
__tablename__ = "UmbrellaPolicy"
id = Column(Integer, primary_key=True)
policy_id = Column(Integer, nullable=False, index=True)
user_defined_name = Column(String(255), nullable=True)
and child is like this
class Site(Base):
__tablename__ = "Site"
id = Column(Integer, primary_key=True)
policy_id = Column(Integer, ForeignKey("Policy.id"))
site_id = Column(String(32), nullable=False, index=True)
policy = relationship("Policy", backref="sites")
You should be able to filter join relations like this
parents = Policy.objects.filter(site__site_id=100)
You can find more info about the Django query API here but its generally of the form where you reference the relation with classname__columnname there are many other ways to filter/query that you can reference in the docs
I used Flask and SQLAlchemy to create an application based on a database. Here is the classes that I have defined:
models.py
class HasTag(db.Model):
tagged_document_id = db.Column(db.Integer, db.ForeignKey('Document.id'), primary_key=True)
document_tag_id = db.Column(db.Integer, db.ForeignKey('Tag.id'), primary_key=True)
class Document(db.Model):
id = db.Column(db.Integer, unique=True, nullable=False, primary_key=True, autoincrement=True)
title = db.Column(db.Text)
tag = db.relationship("Tag",
secondary=HasTag,
back_populates="tagged_document",
lazy="dynamic")
class Tag(db.Model):
id = db.Column(db.Integer, unique=True, nullable=False, primary_key=True, autoincrement=True)
label = db.Column(db.String, nullable=False)
tagged_document = db.relationship("Document",
secondary=HasTag,
back_populates="tag",
lazy="dynamic")
In the application, I have an advanced search form where it is possible to do a full text search through the different fields of the Document table.
routes.py
#app.route("/search")
def search():
keyword = request.args.get("keyword", None)
query = Document.query
if keyword:
query = Document.query.filter(or_(
Document.title.like("%{}%".format(keyword)),
...
))
The thing is, I'd like to be able to search the keyword given by the user also in the label of the tag. I tried something like:
if keyword:
query = Document.query.join(Tag).filter(or_(
Document.title.like("%{}%".format(keyword)),
...,
Tag.label.like("%{}%".format(keyword))
))
But I get this error: AttributeError: 'HasTag' object has no attribute 'foreign_keys'
Can you help me? Thanks!
I have a similar structure in one of my projects, and this is how I define relatioship:
leagues = db.relationship("League",
secondary=LeagueTeamAssociation.__tablename__,
back_populates="teams")
So, You need to provide table name to secondary parameter, either using above syntax (You'll need to add __tablename__ to your HasTag class) or using string "has_tag" (provided that this is the name of the table in the database).
In rails we can simply define relationships with the has_many :through syntax in order to access 2nd, 3rd .. nth degree relations.
In SQLAlchemy however, this seems to be more difficult. I'm trying to avoid going down the route of writing joins, as I find them to be anti-patterns in trying to keep a clean code base.
My tables look like following:
class Message(db.Model):
__tablename__ = 'message'
id = db.Column(db.Integer, primary_key=True)
text = db.Column(db.String())
user_id = db.Column(db.ForeignKey("user.id"))
user = db.relationship('User', backref="messages")
class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String())
class Level(db.Model):
__tablename__ = 'level'
number = db.Column(db.Integer, nullable=False, primary_key=True)
name = db.Column(db.String(), nullable=False, primary_key=True)
users = db.relationship(
"User",
secondary="user_level",
backref="levels")
class UserLevel(db.Model):
__tablename__ = 'user_level'
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True)
number = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(), primary_key=True)
__table_args__ = (
db.ForeignKeyConstraint(
['number', 'name'],
['level.number', 'level.name']
),
)
The idea is that a user can have multiple authorisation levels (e.g. a user can be at level 1, 3 and 6 at the same time). As the data I have does not contain unique sequence numbers for available levels, I had to resort to the use of composite keys to keep the data consistent with future updates.
To get all messages for a level I can currently do something like this:
users = Level.query[0].users
for user in users:
results.append(user.messages)
return results
This gives me all users on a level. But in order to get all messages for a certain level, I have to loop through these users and append them to a results list.
What I'd like to do is:
return Level.query[0].users.messages
This is more like the syntax I am used to from rails. How would one accomplish this in flask-SQLAlchemy?
I have a SQLAlchemy model named NoteType with a relationship named sections. The NoteSection table is joined to the NoteType table through NoteTypeToSectionMap.
I want the sections list on the NoteType model to be ordered by the position field on the NoteTypeToSectionMap model. The code I have below seems to randomly be ordering the sections.
Does anyone know how to get the ordering to work?
Thanks!
class NoteType(ModelAbstract):
__tablename__ = "noteType"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255))
description = db.Column(db.String(255))
sections = db.relationship("NoteSection",
secondary=NoteTypeToSectionMap.__table__,
primaryjoin=id==NoteTypeToSectionMap.__table__.c.noteTypeId,
secondaryjoin=id==NoteTypeToSectionMap.__table__.c.noteSectionId,
order_by=NoteTypeToSectionMap.__table__.c.position)
-
class NoteTypeToSectionMap(ModelAbstract):
__tablename__ = "noteTypeToSectionMap"
id = db.Column(db.Integer, primary_key=True)
noteTypeId = db.Column(db.Integer, db.ForeignKey("noteType.id"))
noteSectionId = db.Column(db.Integer, db.ForeignKey("noteSection.id"))
position = db.Column(db.Integer)
Re-write the relationship as follows.
sections = db.relationship("NoteSection",
secondary=NoteTypeToSectionMap.__table__,
order_by=NoteTypeToSectionMap.__table__.c.position)
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
logs = db.relationship("Logs", uselist=False, backref="user")
class Logs(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users_user.id'))
...
Both ways will work. Basically my question is about the preferable and why. I am talking about this because in my current work i am using always the second option, and i need to decide if is needed to refactor to make the code like the first example.
logs = Logs()
logs.user = current_user._get_current_object()
logs = Logs()
logs.user_id = current_user.get_id()