How to query a parent based on a childs length in sqlalchemy - python

i have a the following model:
class Tables(db.Model): # fixme: rename the table name to table.
__tablename__ = "tables"
id = db.Column(db.Integer, primary_key=True)
store_id = db.Column(db.Integer)
name = db.Column(db.String(64))
active = db.Column(db.Integer, default=0)
orders = db.relationship("Order", backref='table', lazy='dynamic')
So far i have this.
tables = Tables.query.filter_by(store_id=1).all()
free_tables = []
for table in tables:
if len(table.orders.all()) == 0:
free_tables.append(table.id)
what i want are the ids of the tables that have no orders bound to them. Is there a way to write this in a single line? thank you.

Try this:
from sqlalchemy import not_
tables = Tables.query.filter_by(store_id=1)\
.filter(not_(Tables.orders.any())).all()

Related

SQLAlchemy filter_by several item from same column

There are 2 tables in DB with relationship between them by ext column in Player table.
Player id/names are 1000+ and ExtPlayer columns are several too. It takes top 5 players for query its ExtPlayer data together in one or few queries with filter() or filter_by() and avoid to load all ExtPlayer table.
List of top = [x.id for x in player_top]
I tried to query like these or some similar during my trying
ext_data = ExtPlayer.query.filter_by(player_id=top).all() or
db.session.query(ExtPlayer).filter(
or_(ExtPlayer.player_id.like(top1),...,
ExtPlayer.player_id.like(top5))
)
It below models/tables simplified
lass Player(db.Model):
id = db.Column(db.Integer, primary_key=True)
lastseen = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
name = db.Column(db.String(32))
ext = db.relationship('ExtPlayer', backref='extplayer', cascade="all, delete")
class ExtPlayer(db.Model):
created = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
id = db.Column(db.Integer, primary_key=True)
trophies = db.Column(db.Integer)
player_id = db.Column(db.Integer, db.ForeignKey('player.id'))
thanks for any hint.
If I understand correctly you are looking for:
ext_data = db.session.query(ExtPlayer).filter(ExtPlayer.player_id.in_(top)).all()

Python SQLalchemy Join lookup by User

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 ]

SQLAlchemy. How to order on many to many relationship?

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)

SQLAlchemy delete association objects

I'm trying to batch delete objects from an association table by filtering on a column in one of the relationships. I use the following call in SQLAlchemy to make the delete
db.session.query(UserPaper).join(Paper, (UserPaper.paper_id ==
Paper.id)).filter(UserPaper.user_id == user.id).filter(Paper.journal_id
== journal.id).delete()
and it results in the following error
OperationalError: (OperationalError) (1054, "Unknown column 'papers.journal_id'
in 'where clause'") 'DELETE FROM userpapers WHERE userpapers.user_id = %s AND
papers.journal_id = %s' (1L, 1L)
Without the delete at the end, the SQLAlchemy query is
SELECT userpapers.user_id AS userpapers_user_id, userpapers.paper_id AS
userpapers_paper_id, userpapers.created AS userpapers_created,
userpapers.read_at AS userpapers_read_at, userpapers.score AS userpapers_score
FROM userpapers JOIN papers ON userpapers.paper_id = papers.id
WHERE userpapers.user_id = :user_id_1 AND papers.journal_id = :journal_id_1
which is correct. From the error I can see that when I append delete() to the query the join part of SQL statement gets lost and the database doesn't know how to find the papers.journal_id column obviously. What I don't understand is why does that happen?
This is the setup of my ORM objects
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(255), unique=True)
papers = db.relationship("UserPaper", backref=db.backref('users'), lazy='dynamic')
class Paper(db.Model):
__tablename__ = 'papers'
id = db.Column(db.Integer, primary_key = True)
title = db.Column(db.String(1024))
journal_id = db.Column(db.Integer, db.ForeignKey('journals.id'))
class UserPaper(db.Model):
__tablename__ = 'userpapers'
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True)
paper_id = db.Column(db.Integer, db.ForeignKey('papers.id'), primary_key=True)
paper = db.relationship("Paper", backref=db.backref('user_paper'))
read_at = db.Column(db.DateTime)
score = db.Column(db.Integer)
class Journal(db.Model):
__tablename__ = 'journals'
id = db.Column(db.Integer, primary_key = True)
title = db.Column(db.String(100), index = True, unique = True)
papers = db.relationship('Paper', backref = 'journal', lazy = 'dynamic')
I had the same problem with SQLALchemy 0.9 using MySQL 5.6. It looks like a bug/limitation. However, one better way to get arround (in comparison to creating the query, looping through the results and deleting them one by one) is to perform this task in two subsequent queries:
paperQuery = db.session.query(Paper.id)\
filter(Paper.journal_id == journal.id)
baseQuery = db.session.query(UserPaper)\
.filter(UserPaper.paper_id.in_(paperQuery.subquery()))
.filter(UserPaper.user_id == user.id).delete(synchronize_session='fetch')
It worked well for me, it should solve you issue too.

Inserting relationships into a table which connects 3 tables with many to many relationships with SQLALchemy - python

Below you can see how some tables of my database are related.
As you can see the table in the middle is connecting 3 tables with many-to-many relationships...
One gene can be expressed in more than one organ and studied in more than one experimen
In one organ, more than one gene can be expressed and one organ can be studied in more than one experiment.
In one experiment, more than one gene and organ can be studied
I am using SQLAlchemy to insert data. I know how to add a many-to-many relationships with a table that is connecting 2 tables, and more or less I do it like this:
def add_data():
session=Session()
gene = "BRCA2"
gene_to_add = Gene(gene_name = gene)
session.add(gene_to_add)
experiment = "experiment1"
experiment_to_add = Experiment(experimentAccession = experiment)
gene_to_add.experiment_rel.append(experiment_to_add)
organ = "brain"
organ_to_add = Organ(organName = organ)
session.commit()
session.close()
But I don't know how to add a new relationship (organs table in this case). I tried with extend instead of append, but it doesn't works...
Does anyone know how to solve this kind of situation? Maybe the structure of the database should change... any help would be much appreciated
You can always use an Association Object:
class Genes2Experiments2Organs(Base):
__tablename__ = 'genes2experiments2organs'
gene_id = Column(Integer, ForeignKey('genes.id'), primary_key=True)
experiment_id = Column(Integer, ForeignKey('experiments.id'), primary_key=True)
organ_id = Column(Integer, ForeignKey('organs.id'), primary_key=True)
# relationships
gene = relationship("Gene", backref="map")
experiment = relationship("Experiment", backref="map")
organ = relationship("Organ", backref="map")
class Gene(Base):
__tablename__ = 'genes'
id = Column(Integer, primary_key=True)
gene_name = Column(String)
class Experiment(Base):
__tablename__ = 'experiments'
id = Column(Integer, primary_key=True)
experimentAccession = Column(String)
class Organ(Base):
__tablename__ = 'organs'
id = Column(Integer, primary_key=True)
organName = Column(String)
###########################################
def add_data():
session = Session()
gene = "BRCA2"
gene_to_add = Gene(gene_name = gene)
#session.add(gene_to_add)
experiment = "experiment1"
experiment_to_add = Experiment(experimentAccession = experiment)
#session.add(experiment_to_add)
organ = "brain"
organ_to_add = Organ(organName = organ)
#session.add(organ_to_add)
#gene_to_add.experiment_rel.append(experiment_to_add)
assoc_obj_to_add = Genes2Experiments2Organs(
gene = gene_to_add,
experiment = experiment_to_add,
organ = organ_to_add,
)
session.add(assoc_obj_to_add)
session.commit()
session.close()
add_data()

Categories