Flask-SQLAlchemy Multiple Databases to form a query - python

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

Related

List of foreign keys in relationship table flask-sqlalchemy

Hi have two data models (User and Song) and I want users to have several playlists (many to many relationship).
The thing is, inside a playlist there is a user_id and multiple song_ids (the song list could even be empty). However I don't understand how I can make this happen.
Here's what I have so far.
(I removed some fields and the method to simplify)
class User(db.Model):
__tablename__ = "user"
_id = db.Column(db.Integer, primary_key=True)
_first_name = db.Column(db.String, nullable=False)
_last_name = db.Column(db.String, nullable=False)
_username = db.Column(db.String, unique=True, nullable=False)
_email = db.Column(db.String, unique=True, nullable=False)
_password = db.Column(db.String, nullable=False) #TODO: save hashed pwd
_is_admin = db.Column(db.Boolean, default=False)
_accesses = db.relationship(Song.__name__, secondary=Access, backref='_accesses')
_playlists = db.Column(db.JSON) # CHANGE THIS => relationship user-song (?)
class Song(db.Model):
__tablename__ = "song"
_id = db.Column(db.Integer, primary_key=True)
_title = db.Column(db.String, unique=True, nullable=False)
_lyrics = db.Column(db.ARRAY(db.String), nullable=False)
_creator_id = db.Column(db.Integer, nullable=False) #TODO: add user_fk
_accesses = db.relationship(User.__name__, secondary=Access, backref='_accesses')
I've tried to create a relationship table but I just don't understand how to have multiple songs inside the relationship.
Should it be something like this?
playlists = db.Table(
db.Column('id', db.Integer, primary_key=True),
db.Column('name', db.String, nullable=False),
db.Column('user_id', db.Integer, db.ForeignKey(user_fk), nullable= False),
db.Column('songs_ids', db.ARRAY(db.Integer, db.ForeignKey(song_fk))),
db.Column('created_at', db.Datetime, default=datetime.now),
)
Or should I make a relationship song-playlist before making the playlist relationship?

Many to many relationship in flask SQLAlchemy

I'm learning flask and i'm looking to implement a many to many realtionship. I searched on internet but there are different ways,
this is what i have tried so far
class Group(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
class Course(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
class Group_Course(db.Model):
id = db.Column(db.Integer, primary_key=True)
group_id = db.Column(db.Integer, db.ForeignKey(Group.id))
theory_id = db.Column(db.Integer, db.ForeignKey(Course.id))
I'm not sure this is the right way to do it. I'm having issues with delete endpoint. I think that i should add on delete cascade but i don't know how to do it.
there are some sites that add relationships to the table association, so the association table looks like that.
class Group_Course(db.Model):
id = db.Column(db.Integer, primary_key=True)
group_id = db.Column(db.Integer, db.ForeignKey(Group.id))
course_id = db.Column(db.Integer, db.ForeignKey(Course.id))
course = db.relationship(Course, backref="course",cascade='all,
delete')
group = db.relationship(Group, backref="group", cascade='all,
delete`)
there are another examples where they are including a relationship field in both tables like that:
class Group(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
courses = db.relationship("Course", secondary=course_groups,
back_populates="courses")
class Course(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
groups = db.relationship("Group", secondary=course_groups,
back_populates="groups")
So i'm confused, which one is the most correct ?

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 SQL: foreign keys and OnUpdate

I have three SQL tables. Two are independent of each other and third that will have 2 columns (among others) each with relevant id from the first two tables
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
import datetime
class Dad(db.Model):
__tablename__ = "dad"
id = db.Column(db.BigInteger, primary_key=True, autoincrement=True)
name = db.Column(db.String, unique=True)
children = db.relationship('Children', backref='dad', lazy='dynamic')
class Mom(db.Model):
__tablename__ = "mom"
id = db.Column(db.BigInteger, primary_key=True, autoincrement=True)
name = db.Column(db.String, unique=True)
children = db.relationship('Children', backref='mom', lazy='dynamic')
class Children(db.Model):
__tablename__ = "children"
id = db.Column(db.BigInteger, primary_key=True, autoincrement=True)
name = db.Column(db.String, unique=True)
dad_name = db.Column(db.String)
mom_name = db.Column(db.String)
dad_id = db.Column(db.Integer, db.ForeignKey('dad.id'))
mom_id = db.Column(db.Integer, db.ForeignKey('mom.id'))
created_at = db.Column(db.DateTime(6), default=datetime.datetime.utcnow)
updated_at= db.Column(db.DateTime(6), default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
I have 2 issues that I need help with
If I do dad.children.append({'name':'Joe', 'dad_name':'Bill', 'mom_name':'Samantha'}) it attaches the dad.id automatically but not the mom.id. I want it to attach mom.id as well based on her name even if I create it from dad.
When I try to update the record from pgAdmin, it should update the updated_at column with the update time but it doesn't.
Thanks!

flask-sqlalchemy: joined tables and one result object

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)

Categories

Resources