I'm sorry if inverse is not the preferred nomenclature, which may have hindered my searching. In any case, I'm dealing with two sqlalchemy declarative classes, which is a many-to-many relationship. The first is Account, and the second is Collection. Users "purchase" collections, but I want to show the first 10 collections the user hasn't purchased yet.
from sqlalchemy import *
from sqlalchemy.orm import scoped_session, sessionmaker, relation
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
engine = create_engine('sqlite:///:memory:', echo=True)
Session = sessionmaker(bind=engine)
account_to_collection_map = Table('account_to_collection_map', Base.metadata,
Column('account_id', Integer, ForeignKey('account.id')),
Column('collection_id', Integer, ForeignKey('collection.id')))
class Account(Base):
__tablename__ = 'account'
id = Column(Integer, primary_key=True)
email = Column(String)
collections = relation("Collection", secondary=account_to_collection_map)
# use only for querying?
dyn_coll = relation("Collection", secondary=account_to_collection_map, lazy='dynamic')
def __init__(self, email):
self.email = email
def __repr__(self):
return "<Acc(id=%s email=%s)>" % (self.id, self.email)
class Collection(Base):
__tablename__ = 'collection'
id = Column(Integer, primary_key=True)
slug = Column(String)
def __init__(self, slug):
self.slug = slug
def __repr__(self):
return "<Coll(id=%s slug=%s)>" % (self.id, self.slug)
So, with account.collections, I can get all collections, and with dyn_coll.limit(1).all() I can apply queries to the list of collections...but how do I do the inverse? I'd like to get the first 10 collections that the account does not have mapped.
Any help is incredibly appreciated. Thanks!
Many to Many relationship between two tables is achieved by adding an association table such that it has two foreign keys - one from each table's primary key.
Learn about Klaviyo's back-populate feature which allows you to queue people for flow actions retroactively. This is useful when you create a new flow, as back-populating allows you to populate contacts into your flow that would have been queued in real-time had the flow existed earlier.
In Flask-SQLAlchemy, the backref parameter in relationship method allows you to declare a new property under a specified class as seen in the example in their docs: class Person(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(50)) addresses = db.relationship('Address', backref='person ...
I would not use the relationship for the purpose, as technically it it not a relationship you are building (so all the tricks of keeping it synchronized on both sides etc would not work).
IMO, the cleanest way would be to define a simple query which will return you the objects you are looking for:
class Account(Base):
...
# please note added *backref*, which is needed to build the
#query in Account.get_other_collections(...)
collections = relation("Collection", secondary=account_to_collection_map, backref="accounts")
def get_other_collections(self, maxrows=None):
""" Returns the collections this Account does not have yet. """
q = Session.object_session(self).query(Collection)
q = q.filter(~Collection.accounts.any(id=self.id))
# note: you might also want to order the results
return q[:maxrows] if maxrows else q.all()
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With