如何在Flask-SQLAlchemy中同时设置一对多关系和一对一关系? [英] How to set one to many and one to one relationship at same time in Flask-SQLAlchemy?

查看:524
本文介绍了如何在Flask-SQLAlchemy中同时设置一对多关系和一对一关系?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在Flask-SQLAlchemy中同时创建一对一和一对多的关系。我想达到这个目的:



一个组有许多成员和一个管理员。

我做了:

  class Group(db.Model):
id = db.Column(db.Integer,primary_key = True)
name = db.Column(db.String(140),index = True,unique = True)
description = db.Column(db.Text)
created_at = db。 Column(db.DateTime,server_default = db.func.now())

members = db.relationship('User',backref ='group')
admin = db.relationship( 'User',backref ='admin_group',uselist = False)
$ b $ def __repr __(self):
return'< Group%r>'%(self.name)


class User(db.Model):
id = db.Column(db.Integer,primary_key = True)

group_id = db.Column(db .Integer,db.ForeignKey('group.id'))
admin_group_id = db.Column(db.Integer,db.ForeignKey('group.id'))

created_at = db .Column(db.DateTime,server_default = db.func.now ())

然而,我得到一个错误:


sqlalchemy.exc.AmbiguousForeignKeysError:无法确定关系上的父/子表之间的连接
条件Group.members -
有多个连接表的外键路径。指定
'foreign_keys'参数,提供
应该包含对父
表的外键引用的列的列表。
blockquote>

有没有人知道如何做到这一点? 解决方案

因为你已经在你的类之间定义了两个链接 - 一个用户有一个group_id(这是一个外键),而一个组有一个管理员(也是由一个外键定义的)。如果从管理员字段中删除外键,连接不再含糊不清,并且关系正常。这是我解决你的问题(使链接一对一):

 从应用程序导入数据库,应用程序

class Group(db.Model):
id = db.Column(db.Integer,primary_key = True)
name = db.Column(db.String(140),index = True,unique = True)
description = db.Column(db.Text)
created_at = db.Column(db.DateTime,server_default = db.func.now())
admin_id = db.Column(db.Integer)#,db.ForeignKey('user.id'))
members = db.relationship('User',backref ='group')

def admin(self):
return User.query.filter_by(id = self.admin_id).first()
$ b $ class User(db.Model):
id = db .Column(db.Integer,primary_key = True)
name = db.Column(db.String(80),unique = True)
group_id = db.Column(db.Integer,db.ForeignKey 'group.id'))
created_at = db.Column(db.DateTime,server_default = db.func.now())

这个的一个缺点就是这个群体的目标ct没有一个整洁的 admin 成员对象,你可以使用 - 你必须调用函数 group.admin()检索管理员。但是,该组可以有许多成员,但只有其中一个可以成为管理员。很明显,没有DB级别的检查来确保管理员实际上是组的成员,但是您可以将该检查添加到setter函数中 - 可能类似于:

#setter方法
def admin(self,user):
如果user.group_id == self.id:
self.admin_id = user.id

#getter method
def admin(self):
返回User.query.filter_by(id = self.admin_id).first()


I'm trying to create one-to-one and one-to-many relationship at the same time in Flask-SQLAlchemy. I want to achieve this:

"A group has many members and one administrator."

Here is what I did:

class Group(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(140), index=True, unique=True)
    description = db.Column(db.Text)
    created_at = db.Column(db.DateTime, server_default=db.func.now())

    members = db.relationship('User', backref='group')
    admin = db.relationship('User', backref='admin_group', uselist=False)

    def __repr__(self):
        return '<Group %r>' % (self.name)


class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)

    group_id = db.Column(db.Integer, db.ForeignKey('group.id'))
    admin_group_id = db.Column(db.Integer, db.ForeignKey('group.id'))

    created_at = db.Column(db.DateTime, server_default=db.func.now())

However I got an error:

sqlalchemy.exc.AmbiguousForeignKeysError: Could not determine join condition between parent/child tables on relationship Group.members - there are multiple foreign key paths linking the tables. Specify the 'foreign_keys' argument, providing a list of those columns which should be counted as containing a foreign key reference to the parent table.

Does anyone know how to do that properly?

解决方案

The problem you're getting comes from the fact that you've defined two links between your classes - a User has a group_id (which is a Foreign Key), and a Group has an admin (which is also defined by a Foreign Key). If you remove the Foreign Key from the admin field the connection is no longer ambiguous and the relationship works. This is my solution to your problem (making the link one-to-one):

from app import db,app

class Group(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(140), index=True, unique=True)
    description = db.Column(db.Text)
    created_at = db.Column(db.DateTime, server_default=db.func.now())
    admin_id = db.Column(db.Integer) #, db.ForeignKey('user.id'))
    members = db.relationship('User', backref='group')

    def admin(self):
        return User.query.filter_by(id=self.admin_id).first()

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), unique=True)
    group_id = db.Column(db.Integer, db.ForeignKey('group.id'))
    created_at = db.Column(db.DateTime, server_default=db.func.now())

The one drawback to this is that the group object doesn't have a neat admin member object you can just use - you have to call the function group.admin() to retrieve the administrator. However, the group can have many members, but only one of them can be the administrator. Obviously there is no DB-level checking to ensure that the administrator is actually a member of the group, but you could add that check into a setter function - perhaps something like:

# setter method
def admin(self, user):
    if user.group_id == self.id:
        self.admin_id = user.id

# getter method
def admin(self):
    return User.query.filter_by(id=self.admin_id).first()

这篇关于如何在Flask-SQLAlchemy中同时设置一对多关系和一对一关系?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆