SqlAlchemy - two foreign keys and bidirectional relationship - python

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?

Related

Sqlalchemy: How to manage multiple tables (Python)?

I need to create four tables. First table include the "Users", second include "Group Name", the second table should be related to "Users" table. Third table include "Groups Columns Data" which is related to "Group" table, and finally the fourth table is "Group Borrow Lending Data" which is also linked to third table i.e "Groups".
But it's throwing an error when I try to get specific username.
TypeError: sqlalchemy.exc.InvalidRequestError: Can't compare a
collection to an object or collection; use contains() to test for
membership.
#v1.get("/get-specific-groups/{group_name}", tags=["GROUP"])
def get_specific_groups(group_name: str, current_user: CreateGroupSchema = Depends(get_current_user), db: Session = Depends(get_db)):
return db.query(User, Group, GroupColumnsData).join(GroupColumnsData).filter(Group.owner_username == current_user.get("username")).all()
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
username = Column(String(60), unique=True, nullable=False)
email = Column(String(80), unique=True, nullable=False)
password = Column(String(140), nullable=False)
groups = relationship("Group", backref="owner")
class Group(Base):
__tablename__ = "groups"
id = Column(Integer, primary_key=True, index=True)
group_name = Column(String(60), unique=True, nullable=False)
description = Column(String, nullable=False)
owner_username = Column(String, ForeignKey("users.username"), default=User.username)
group_username = relationship("GroupColumnsData", backref="group_owner")
class GroupColumnsData(Base):
__tablename__ = "groupsColumnsData"
id = Column(Integer, primary_key=True, index=True)
payee_name = Column(String(60))
item_name = Column(String(100))
amount_spent = Column(Integer)
owner_group = Column(String, ForeignKey("groups.group_name"), default=Group.group_name)
class GroupBorrowLendingData(Base):
__tablename__ = "groupsBorrowLendingData"
id = Column(Integer, primary_key=True, index=True)
lender = Column(String(60))
money_borrowed = Column(Integer)
borrower = Column(String(60))
owner_group = Column(String, ForeignKey("groups.group_name"), default=Group.group_name)
The Following code worked!
#v1.get("/get-specific-groups/{group_name}", tags=["GROUP"])
def get_specific_groups(group_name: str, current_user: CreateGroupSchema = Depends(get_current_user), db: Session = Depends(get_db)):
return db.query(Group).filter(Group.owner_username == current_user.get("username")).filter(Group.group_name.match(group_name)).all()

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)

SqlAlchemy Entity class has no property when joining

I'm trying to do the following query:
stats = Session.query(PlayerMatchStats).join(Match, Match.id == PlayerMatchStats.match_id
).filter_by(player=self).order_by(Match.date.desc()).limit(5).all()
These are some parts of the relevant models:
class PlayerMatchStats(Base):
__tablename__ = 'players_stats'
id = Column(Integer, primary_key=True)
player_id = Column(ForeignKey('players.id'), index=True, nullable=False)
player = relationship('Player', backref='stats')
match_id = Column(ForeignKey('matches.id'), index=True, nullable=False)
match = relationship('Match', backref='players_stats')
team_id = Column(ForeignKey('teams.id'), index=True, nullable=False)
team = relationship('Team', backref='players_matches_stats')
class Match(Base):
__tablename__ = 'matches'
id = Column(Integer, primary_key=True)
league_id = Column(ForeignKey('leagues.id'), nullable=False, index=True)
home_team_id = Column(ForeignKey('teams.id'), nullable=False, index=True)
home_team = relationship('Team', foreign_keys=[home_team_id], backref='home_matches')
away_team_id = Column(ForeignKey('teams.id'), nullable=False, index=True)
away_team = relationship('Team', foreign_keys=[away_team_id], backref='away_matches')
class Player(Base):
__tablename__ = 'players'
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False, index=True)
When trying to perform the query, the error I receive is: Entity '<class 'model.overview.Match'>' has no property 'player'
Sqlalchemy thinks that you're trying to filter based on a property on Match when you really need to filter on a property of PlayerMatchStats. You can explicitly tell SQLAlchemy which model you are referring to using the "filter" method instead of "filter_by". In summary:
stats = Session.query(PlayerMatchStats).join(Match, Match.id==PlayerMatchStats.match_id)\
.filter(PlayerMatchStats.player=self).order_by(Match.date.desc()).limit(5).all()
This is of course assuming that "self" is a Player object

sqlalchemy constraint in models inheritance

I have two simple models:
class Message(Backend.instance().get_base()):
__tablename__ = 'messages'
id = Column(Integer, primary_key=True, autoincrement=True)
sender_id = Column(Integer, ForeignKey('users.id'))
content = Column(String, nullable=False)
class ChatMessage(Message):
__tablename__ = 'chat_messages'
id = Column(Integer, ForeignKey('messages.id'), primary_key=True)
receiver_id = Column(Integer, ForeignKey('users.id'))
How to define constraint sender_id!=receiver_id?
This doesn't seem to work with joined table inheritance, I've tried and it complains that the column sender_id from Message doesn't exist when creating the constraint in ChatMessage.
This complaint makes sense, since sender_id wouldn't be in the same table as receiver_id when the tables are created, so the foreign key relationship would need to be followed to check the constraint.
One option is to make ChatMessage a single table.
Use CheckConstraint, placed in table args.
class ChatMessage(Base):
__tablename__ = 'chat_messages'
id = sa.Column(sa.Integer, primary_key=True)
sender_id = sa.Column(sa.Integer, sa.ForeignKey(User.id))
receiver_id = sa.Column(sa.Integer, sa.ForeignKey(User.id))
content = sa.Column(sa.String, nullable=False)
__table_args__ = (
sa.CheckConstraint(receiver_id != sender_id),
)

Categories

Resources