class Show(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(200), unique=True, nullable=False)
studio = db.relationship("ShowStudio", backref="show", cascade="delete")
class Studio(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), unique=True, nullable=False)
show = db.relationship("ShowStudio", backref="studio", cascade="delete")
class ShowStudio(db.Model):
show_id = db.Column(db.Integer, db.ForeignKey(Show.id, ondelete="CASCADE"), primary_key=True)
studio_id = db.Column(db.Integer, db.ForeignKey(Studio.id, ondelete="CASCADE"), primary_key=True)
studio = Studio(name="asd")
db.session.add(studio)
s = Show(title="a", studio=[studio])
db.session.flush()
db.session.add(s)
db.session.commit()
When I run it, it throws
sqlalchemy.orm.exc.FlushError: Attempting to flush an item of type as a member of collection "Studio.show". Expected an object of type or a polymorphic subclass of this type.
I follow the answer from here. I do not understand what cause the error. Any helps are welcome.
There'd seem to be a little mixup between a many to many relationship and using the association object pattern (which is a variant of many to many). Given the way you've configured your models Show.studio is actually a one to many relationship with ShowStudio, and so it expects a collection of ShowStudio objects, not Studio:
studio = Studio(name="asd")
db.session.add(studio)
showstudio = ShowStudio(studio=studio)
# You've disabled save-update cascade, so you have to
# add the association object to the session manually!
db.session.add(showstudio)
s = Show(title="a", studio=[showstudio])
db.session.add(s)
db.session.commit()
For your original attempt to work you'd define a many to many relationship between Show and Studio using the table underlying ShowStudio as the secondary:
class Show(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(200), unique=True, nullable=False)
studio = db.relationship("Studio", secondary="show_studio",
back_populates="show")
class Studio(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), unique=True, nullable=False)
show = db.relationship("Show", secondary="show_studio",
back_populates="studio")
class ShowStudio(db.Model):
show_id = db.Column(db.Integer, db.ForeignKey(Show.id, ondelete="CASCADE"),
primary_key=True)
studio_id = db.Column(db.Integer, db.ForeignKey(Studio.id, ondelete="CASCADE"),
primary_key=True)
Since there's no explicit __tablename__ in ShowStudio Flask-SQLAlchemy automatically sets it for you to show_studio.
Related
I'm trying to build a dynamic filter that combines three tables in flask-sqlalchemy. I can get it working with one table but I'm struggling to see how this should work with more than one table.
Presently I've tried to join the table UserInClub and User but I get the error TypeError: 'BaseQuery' object is not callable. I've tried to do the join before I start any queries but I can't figure out how I can then construct a dynamic query as I'm trying to do below. Also is it possible to use a group_by to have all users within a single list if they are in multiple clubs?
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
created_by = db.Column(db.String(64), index=True, unique=True, nullable=False)
user_name = db.Column(db.String(64), index=True, unique=True, nullable=False)
#classmethod
def filter_user(
cls,
created_by,
club_name=None,
user_name=None,
):
query = cls.query.filter_by(created_by=created_by)
if user_name:
query = query.filter_by(user_name=user_name)
if club_name:
query = query(User, UserInClub
).filter(User.id==UserInClub.id
).filter(Club.club_name=club_name)
return query.all()
class Club(db.Model):
id = db.Column(db.Integer, primary_key=True)
club_name = db.Column(db.String(100), unique=True, nullable=False)
class UserInClub(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
club_id = db.Column(db.Integer, db.ForeignKey('club.id'), nullable=False)
I am creating an application that will gather requirements for a number of different 'Types' of items, and can't figure out how to structure the Flask-SQLAlchemy ORM Model relationship(s).
I have the following Classes:
ItemSize - A 'Type', think of liek a T-Shirt size.
class ItemSize(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80), unique=True, nullable=False)
date_created = db.Column(db.Date(), default=datetime.now())
height = db.Column(db.Integer, nullable=True)
depth = db.Column(db.Integer, nullable=True)
width = db.Column(db.Integer, nullable=True)
ItemSet - A collection of a particular ItemSize, stores relationship to ItemSize and a Count.
(Eg. ItemSize: 'A', Count: 2)
class ItemSet(db.Model):
id = db.Column(db.Integer, primary_key=True)
size = db.Column(db.Integer, db.ForeignKey('itemsizes.id'), nullable=True)
count = db.Column(db.Integer, nullable=False)
Requirements - A collection of many ItemSets.
(Eg. ItemSets [1, 2, 3, 4, 5])
class Specification(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80), unique=True, nullable=False)
comments = db.Column(db.String(255), nullable=True)
# THIS IS THE BIT I AM UNSURE OF
# Need this to a collection of Many ItemSets
# Will the below work?
requirements = db.relationship('ItemSet', uselist=True, backref='itemsets')
The above gives me the following error when trying to create any objects:
sqlalchemy.exc.InvalidRequestError: One or more mappers failed to initialize - can't proceed with initialization of other mappers. Triggering mapper: 'mapped class Specification->specifications'. Original exception was: Could not determine join condition between parent/child tables on relationship Specification.requirements - there are no foreign keys linking these tables. Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or specify a 'primaryjoin' expression.
Does anyone know how to achieve this kind of relationship?
Specification.requirements -> [Array of ItemSets]
Any pointers very much appreciated.
You need to modify these 2 classes:
class Specification(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80), unique=True, nullable=False)
comments = db.Column(db.String(255), nullable=True)
# THIS IS THE BIT I AM UNSURE OF
# Need this to a collection of Many ItemSets
# Will the below work?
requirements = relationship("ItemSet", back_populates="spec")
class ItemSet(db.Model):
id = db.Column(db.Integer, primary_key=True)
size = db.Column(db.Integer, db.ForeignKey('itemsizes.id'), nullable=True)
count = db.Column(db.Integer, nullable=False)
spec_id = Column(db.Integer, ForeignKey('spec.id'))
spec = relationship("Specification", back_populates="requirements")
I am new to using Flask SQLAlchemy and I have a few questions on how can how can I link separate databases together to form a query.
I have 3 databases: User, Homework, Questions, where 1 user can have many homework and 1 homework can have many questions. I have made 3 separate .py files for the 3 classes and each file calls simple functions like query.all(), and some simple filtering.
I have previously learned MySQL and I am wondering how can I create an SQLAlchemy equivalent of the following query:
SELECT * FROM user, homework, questions
WHERE user.user_id = homework.user_id
AND homework.homework_id = questions.homework_id
My question is how do I go about achieving this? Do I make a new file and find a way to bind these databases together or is there a more optimal way of doing it?
Also, how do I go about retrieving aggregated function values? For instance, the average marks one would get for each homework.
User.py
class User(db.Model):
__tablename__ = 'user'
user_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(20), nullable=False)
Homework.py
class Homework(db.Model):
__tablename__ = 'homework'
homework_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
user_id= db.Column(db.Integer, nullable=False)
subject = db.Column(db.String(20), nullable=False)
Question.py
class Question(db.Model):
__tablename__ = 'question'
question_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
homework_id = db.Column(db.Integer, nullable=False)
marks = db.Column(db.Integer, nullable=False)
You can create relationships amongst your tables using the following
class User(db.Model):
__tablename__ = 'user'
user_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(20), nullable=False)
class Homework(db.Model):
__tablename__ = 'homework'
homework_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.user_id'), nullable=False)
subject = db.Column(db.String(20), nullable=False)
class Question(db.Model):
__tablename__ = 'question'
question_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
homework_id = db.Column(db.Integer, db.ForeignKey('homework.homework_id'), nullable=False)
marks = db.Column(db.Integer, nullable=False)
Then you can access info from a given table using the following
insert your desired user_id in replace for xxx
user_object = User.query.filter_by(user_id=xxx).first()
username = user_object.username
user_id_value = user_object.user_id
homework_object = Homework.query.filter_by(user_id=user_id_value).first()
subject = homework_object.subject
homework_id_value = homework_object.homework_id
question_object = Question.query.filter_by(homework_id=homework_id_value).first()
marks = question_object.marks
I am making a wishlist app and I want to have db schema like bellow, but I can't figure out how to make the joins in sqlalchemy (this is the first time I am using sqlalchemy).
DB schema
(user : wish = 1 : N)
When I select a user, I want to get a list of wishes and each wish may contain a different user (an arranger of the wish)
So I could do something like this
first_user = User.query.get(1)
user_wishes = first_user.wishes.all()
for wish in user_wishes:
if wish.arranger is not None:
print(wish.id, wish.owner.id, wish.arranger.id)
else:
print(wish.id, wish.owner.id)
I have looked up some tutorials, but I only found simple relations.
I need a relation from User to Wish and in the Wish, back to both the UserWishOwner (the user from which I got here) a UserWishArranger (if there is any).
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
wishes = db.Column(db.relationship('Wish', backref='owner', lazy='dynamic'))
class Wish(db.Model):
id = db.Column(db.Integer, primary_key=True)
owner_id = db.Column(db.Integer, db.ForeignKey('user.id'), index=True)
arranger_id = db.Column(db.Integer, db.ForeignKey('user.id'), index=True)
arranger = relationship("User", foreign_keys=[arranger_id])
I have come up with some code, but am a bit confused, because owner_id and arranger_id are the same...
What do I need to do, to make this work?
Just like this
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
wishes = db.relationship('Wish', backref='owner', lazy='dynamic', foreign_keys="[Wish.owner_id]")
class Wish(db.Model):
id = db.Column(db.Integer, primary_key=True)
owner_id = db.Column(db.Integer, db.ForeignKey('user.id'), index=True)
arranger_id = db.Column(db.Integer, db.ForeignKey('user.id'), index=True)
arranger = db.relationship("User", foreign_keys=[arranger_id])
I am coming from a python-django and am trying to get a grasp on flask-SQLAlchemy:
class Author(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(128), nullable=False)
class Book(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
title = db.Column(db.String(128), nullable=False)
author = db.Column(db.Integer, db.ForeignKey('author.id'), nullable=False)
I want to get a joined result list:
results = Book.query.filter(Author.name=='tom')
for result in results:
print(result.title, result.???.name)
How do I access the fields of the joined tables?
I figured it out:
class Book(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
title = db.Column(db.String(128), nullable=False)
author_id = db.Column(db.Integer, db.ForeignKey('author.id'), nullable=False)
author = relationship("Author")
I needed to add the line
author = relationship("Author")
to the model. It seems to be necessary to declare the relationship on the object level. I did miss this.
Now the line can be:
print(result.title, result.author.name)