[英]SQLAlchemy User Many to Many Relationship
I am working on a user structure where a user can have parents and children that consist of user objects.我正在研究一个用户结构,其中用户可以拥有由用户对象组成的父母和孩子。 I have been trying to get the following to work in multiple different ways in SQLAlchemy and Flask.
我一直在尝试让以下内容在 SQLAlchemy 和 Flask 中以多种不同的方式工作。
Here is an example of how I want to structure this:这是我要如何构建它的示例:
UserTable
id | name
---+-----
1 | Kim
2 | Tammy
3 | John
4 | Casey
5 | Kyle
UserRelationship
id | parent_user_id | child_user_id
---+----------------+---------------
1 | 1 | 2
2 | 1 | 3
3 | 4 | 2
Where Kim is the parent to Tammy and John. Kim 是 Tammy 和 John 的父母。 Casey is the parent of Tammy.
凯西是塔米的父母。 Tammy is the child of Kim and Casey.
塔米是金和凯西的孩子。 John is the child of Kim.
约翰是金的孩子。 Kyle has no children nor parents.
凯尔没有孩子也没有父母。
My error reads:我的错误是:
sqlalchemy.exc.AmbiguousForeignKeysError: Could not determine join condition
between parent/child tables on relationship User.parents - there are multiple
foreign key paths linking the tables via secondary table 'user_relationship'.
Specify the 'foreign_keys' argument, providing a list of those columns which
should be counted as containing a foreign key reference from the secondary
table to each of the parent and child tables.
My model.py
file looks like:我的
model.py
文件如下所示:
user_relationship = db.Table(
'user_relationship',
db.Model.metadata,
db.Column('child_user_id', db.Integer, db.ForeignKey('user.id')),
db.Column('parent_user_id', db.Integer, db.ForeignKey('user.id'))
)
class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True, unique=True, nullable=False)
email = db.Column(db.String(120), unique=True)
pwdhash = db.Column(db.String(54))
parents = relationship('User',
secondary=user_relationship,
backref=db.backref('children'),
cascade="all,delete")
This might not be the best way to handle many to many hierarchical user relationships in Flask or SQLAlchemy. Any insight on how to build this out would be great.这可能不是处理 Flask 或 SQLAlchemy 中多对多分层用户关系的最佳方式。任何关于如何构建它的见解都会很棒。
Thank you谢谢
db.Table
is mainly used when there is a Many to Many
relation between two different entities. db.Table
主要用于两个不同实体之间存在Many to Many
关系时。 Here both parent and child are User
s. 这里父母和孩子都是
User
。
In your case, below code would be fine: 就您而言,下面的代码会很好:
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True, unique=True, nullable=False)
email = db.Column(db.String(120), unique=True)
pwdhash = db.Column(db.String(54))
class Parent(db.Model):
__tablename__ = 'parents'
child_id = db.Column(db.Integer, db.Foreignkey('users.id'))
parent_id = db.Column(db.Integer, db.Foreignkey('users.id'))
child = db.relationship('User', foreign_keys=[child_id], backref = 'parents')
flask_sqlalchemy
is written on top of SQLAlchemy
, and there is a nice elaboration of this issue here (Handling Multiple Join Paths) in SQLAlchemy's website. flask_sqlalchemy
写在上面SQLAlchemy
,有这个问题的一个很好的阐述在这里 (处理多个连接路径)在SQLAlchemy的网站。
primaryjoin
and secondaryjoin
args.primaryjoin
和secondaryjoin
参数。 Recently I faced similar issue, although I see documentation and accepted answer s recommend to user Parent
model instead of creating a relationship table, it didn't make sense for me to create a separate model for just storing a relationship since my all models inherit from BaseModel
and I don't want this relationship to get BaseModel
's additional features.最近我遇到了类似的问题,虽然我看到文档和接受的答案建议用户
Parent
model 而不是创建关系表,但我创建一个单独的 model 来存储关系是没有意义的,因为我的所有模型都继承自BaseModel
和我不希望这种关系获得BaseModel
的附加功能。 Mainly because my BaseModel
has id
by default and BaseTable
does not contain id
主要是因为我的
BaseModel
默认有id
而BaseTable
没有包含id
So, I prefer creating a separate Sqlalchemy Table for relationship instead of Model.所以,我更喜欢为关系创建一个单独的 Sqlalchemy 表,而不是 Model。
To accomplish it you may use primaryjoin
and secondaryjoin
arguments as following.要完成它,您可以使用
primaryjoin
和secondaryjoin
arguments,如下所示。 I have many-to-one relationship of investors with relationship_manager.我与 relationship_manager 之间存在多对一的投资者关系。 To make it many-to-many you may remove
unique=True
from investor_id
in relation table and remove uselist=False
from relationship_manager in User model.要使其成为多对多,您可以从关系表中的
investor_id
中删除unique=True
,并从用户 model 中的 relationship_manager 中删除uselist=False
。
# user.py
from database.relationships.relationship_managers import relationship_managers
class User(BaseModel):
id = Column(Integer, primary_key=True)
relationship_manager = relationship(
"User",
secondary=relationship_managers,
uselist=False,
primaryjoin=("relationship_managers.c.investor_id == User.id"),
secondaryjoin=("relationship_managers.c.rel_manager_id == User.id"),
backref="investors"
)
# relationship_managers.py
relationship_managers = BaseTable(
"relationship_managers",
Column("investor_id", Integer, ForeignKey('user.id', ondelete="CASCADE"), unique=True),
Column("rel_manager_id", Integer, ForeignKey('user.id', ondelete="CASCADE")),
)
Here, primaryjoin
performs the first join with investor_id and gets the record User record, but this is not sufficient for us.在这里,
primaryjoin
执行第一次与 investor_id 的连接并获取记录用户记录,但这对我们来说还不够。 So, we need secondaryjoin
to specifically get the relationship_manager's id.所以,我们需要
secondaryjoin
专门获取 relationship_manager 的 id。
Feel free to comment and suggest if any doubts.如有任何疑问,请随时发表评论并提出建议。 Hopefully this helps anyone who has Models and Tables both in their Project using Sqlalchemy. :)
希望这可以帮助使用 Sqlalchemy 在其项目中同时拥有模型和表格的任何人。:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.