flask-sqlalchemy: joined tables and one result object - python

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)

Related

SqlAlchemy - two foreign keys and bidirectional relationship

I have a small base for a website for a real estate agency, below are two tables:
class Person(Base):
__tablename__ = "people"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False)
surname = Column(String, nullable=False)
city = Column(String, nullable=True)
# TODO - add lists
class Property(Base):
__tablename__ = "properties"
id = Column(Integer, primary_key=True, index=True)
city = Column(String, nullable=False)
address = Column(String, nullable=False)
owner_id = Column(Integer, ForeignKey("people.id"), nullable=False)
manager_id = Column(Integer, ForeignKey("people.id"), nullable=False)
# TODO - rework
owner = relationship("Person", foreign_keys=[owner_id], backref=backref("owners"))
manager = relationship("Person", foreign_keys=[manager_id], backref=backref("managers"))
I would like my 'Person' object to have two lists of properties - "owned_properites" and "properties_to_manage" (without losing reference to the owner/manager in the 'Property' class). But i don't know how to define a relationship to make auto mapping work properly.
If the class 'Property' only had one foreign key to the 'Person', for example - only "owner_id" key and "owner" object then it would be simple:
#in Property
owner_id = Column(Integer, ForeignKey("people.id"), nullable=False)
owner = relationship("Person", back_populates="property")
#in Person
owned_properties = relationship("Property", back_populates="owner")
But how to do the same with two keys, as shown at the beginning?

Flask sqlalchemy how to manage additional information in a many-to-many relationship

Consider the following many-to-many relationship:
class Hashes(db.Model):
id = db.Column(db.Integer, primary_key=True)
hash = db.Column(db.String, nullable=False, unique=True)
xref_hashes_users = db.Table("xref_hashes_users",
db.Column('hash', db.ForeignKey('hashes.id'), primary_key=True),
db.Column('user', db.ForeignKey('user.id'), primary_key=True))
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String)
hashes = db.relationship("Hashes", secondary="xref_hashes_users", backref="users")
Let's say I want to allow users to store some additional information about their hashes, perhaps a label. It makes sense to me that given this is a user-specific piece of information about a hash, it would go in the association table like:
xref_hashes_users = db.Table("xref_hashes_users",
db.Column('hash', db.ForeignKey('hashes.id'), primary_key=True),
db.Column('user', db.ForeignKey('user.id'), primary_key=True),
db.Column('label', db.String))
Given this schema, is it possible to use the ORM to add/remove/update labels? How would I do this?
It looks like the answer is to use an Association Object to store the extra data.
https://docs-sqlalchemy.readthedocs.io/ko/latest/orm/basic_relationships.html#association-object
So my example becomes:
class Hashes(db.Model):
id = db.Column(db.Integer, primary_key=True)
hash = db.Column(db.String, nullable=False, unique=True)
users = db.relationship("UserHashAssociation", back_populates="hashes")
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String)
hashes = db.relationship("UserHashAssociation", back_populates="users")
class UserHashAssociation(db.Model):
__tablename__ = "xref_hashes_users"
user_id = db.Column(db.Integer, db.ForeignKey("user.id"), primary_key=True)
hash_id = db.Column(db.Integer, db.ForeignKey("hashes.id"), primary_key=True)
label = db.Column(db.String)
users = db.relationship("User", back_populates="hashes")
hashes = db.relationship("Hashes", back_populates="users")
Then I am able to update the label like:
hash = Hashes(hash=hash_string)
user_hash_association = UserHashAssociation(label="foo", user_id=user.id)
hash.users.append(user_hash_association)
db.session.add(hash)
db.session.commit()

Flask-SQLAlchemy: User role Models and relationship

I am trying to create a Flask-SqlAlchemy database model and need users to be linked to a single role. Example roles: "User", "Admin", "Moderator".
Surely I could use a simple relatioship, which just adds a user_role_id Column to the User, but I would also like to track the last modification.
class User:
id = db.Column(db.Integer, primary_key=True)
class UserRole:
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), nullable=False)
class UserRoleLink(db.Model):
user_id = db.Column(db.Integer, db.ForeignKey("user.id"), primary_key=True)
user_role_id = db.Column(db.Integer, db.ForeignKey("user_role.id"), primary_key=True)
last_modified = db.Column(db.DateTime, nullable=False, default=datetime.now, onupdate=datetime.now)
How do I complete this model with the required relationships? Also I would like to ensure, that a User can only have one Role, but Roles can be used as often as required.
Thank you in advance!
I think it should works for you:
class User:
id = db.Column(db.Integer, primary_key=True)
class UserRole:
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), nullable=False, unique=True)
role_link = db.relationship('UserRoleLink', cascade='all, delete-orphan', uselist=False)
class UserRoleLink(db.Model):
user_id = db.Column(db.Integer, db.ForeignKey("user.id"), primary_key=True)
user_role_id = db.Column(db.Integer, db.ForeignKey("user_role.id"), primary_key=True)
last_modified = db.Column(db.DateTime, nullable=False, default=datetime.now, onupdate=datetime.now)

Flask-SQLAlchemy Multiple Databases to form a query

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

Sqlalchemy and many to many relationship linking two tables

I am having trouble creating a link between the Orders and ProductOrders table with Sqlalchemy. I need to link order_id, which exists in both Orders table and ProductOrders table in order to query orders from a store and also get the product data as well. I am working with BigCommerce API so order_id is only unique to each specific store and not unique globally like Shopify API.
The order_id is the link I wish to create, but it only unique for each store.id in the Store table so I can't do a simple join as the order_id is no unique on its own. Do I use the Store table to link this many to many relationship, or do I need to use the StoreUser table that is already linking the store_id and user_id together? I am so confused. Any help would be greatly appreciated.
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
bc_id = db.Column(db.Integer, nullable=False)
email = db.Column(db.String(120), nullable=False)
storeusers = relationship("StoreUser", backref="user")
class StoreUser(db.Model):
id = db.Column(db.Integer, primary_key=True)
store_id = db.Column(db.Integer, db.ForeignKey('store.id'), nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
admin = db.Column(db.Boolean, nullable=False, default=False)
class Store(db.Model):
id = db.Column(db.Integer, primary_key=True)
store_hash = db.Column(db.String(16), nullable=False, unique=True)
access_token = db.Column(db.String(128), nullable=False)
scope = db.Column(db.Text(), nullable=False)
admin_storeuser_id = relationship("StoreUser",
primaryjoin="and_(StoreUser.store_id==Store.id, StoreUser.admin==True)")
storeusers = relationship("StoreUser", backref="store")
store_orders_id = relationship("Orders",
primaryjoin="(Orders.store_id==Store.id)")
store_orders = relationship("Orders", backref="store", cascade="all, delete")
store_product_orders_id = relationship("ProductOrders",
primaryjoin="(ProductOrders.store_id==Store.id)")
store_product_orders = relationship("ProductOrders", backref="store", cascade="all, delete")
class Orders(db.Model):
id = db.Column(db.Integer, primary_key=True)
store_id = db.Column(db.Integer, db.ForeignKey('store.id'), nullable=False)
order_id = db.Column(db.Integer,nullable=False)
date_created = db.Column(db.DateTime, nullable=False)
class ProductOrders(db.Model):
id = db.Column(db.Integer, primary_key=True)
store_id = db.Column(db.Integer, db.ForeignKey('store.id'), nullable=False)
order_id = db.Column(db.Integer, nullable=False)
product_id = db.Column(db.Integer, nullable=False)
base_price = db.Column(db.Float, nullable=False)
I think you would need a multi-column primary key, so the unique constraint is order_id+store_id
This answer shows multi column primary keys in sqlalchemy: https://stackoverflow.com/a/9036128/210101
And this one shows joining on multiple columns: https://stackoverflow.com/a/51164913/210101

Categories

Resources