python SQLAlchemy用户多对多关系

z6psavjg  于 2023-02-02  发布在  Python
关注(0)|答案(2)|浏览(195)

我正在开发一个用户结构,其中用户可以拥有由用户对象组成的父对象和子对象。我一直在尝试在SQLAlchemy和Flask中以多种不同的方式实现以下功能。
下面是一个我想要如何组织的例子:

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

其中金是塔米和约翰的父母。凯西是塔米的父母。塔米是金和凯西的孩子。约翰是金的孩子。凯尔没有孩子也没有父母。
我的错误是:

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.

我的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")

这可能不是在Flask或SQLAlchemy中处理多对多层次用户关系的最佳方法,任何关于如何构建这种关系的见解都是很好的。
谢谢

vawmfj5a

vawmfj5a1#

db.Table主要用于两个不同实体之间存在Many to Many关系的情况,这里的父子都是User
在您的情况下,下面的代码就可以了:

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是在SQLAlchemy的基础上编写的,在SQLAlchemy的网站上here(处理多个连接路径)有关于这个问题的详细说明。

mf98qq94

mf98qq942#

使用primaryjoinsecondaryjoin参数。

最近我遇到了类似的问题,虽然我看到了文档并接受了建议用户Parent模型的答案,而不是创建关系表,创建一个单独的模型来存储关系对我来说没有意义,因为我的所有模型都是从BaseModel继承的,并且我不希望这个关系获得BaseModel的附加特性。主要是因为我的BaseModel默认有id,而BaseTable不包含id
因此,我更喜欢为关系创建一个单独的Sqlalchemy Table,而不是Model。
要实现这一点,您可以使用primaryjoinsecondaryjoin参数,如下所示。我有多对一关系的投资者与relationship_manager。要使它成为多对多,您可以删除unique=Trueinvestor_id的关系表,并删除uselist=False从用户模型的relationship_manager。

# 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")),
)

这里,primaryjoin执行与investor_id的第一次连接,并获得记录User记录,但这对我们来说是不够的,因此,我们需要secondaryjoin专门获得relationship_manager的id。
如果有任何疑问,请随时发表评论和建议。希望这能帮助任何使用Sqlalchemy在项目中同时拥有模型和表的人。:)

相关问题