Flask-Admin 中的简单多对多问题
Simple Many-to-Many issue in Flask-Admin
我正在将 Flask-Admin 添加到现有的 Flask 应用程序中(使用 Python 3,以及 MySQL 和 SQLAlchemy),我根本不知道如何获得多对-许多关系才能正确呈现。我在这里阅读了很多关于此的问题,看起来我正在遵循正确的做法。
我有一个Quotation
table、一个Subject
table和一个QuotationSubject
table,必须是实际的class 而不是关联 table,但我不关心关联 table 中用于此目的的额外列;它们是 last_modified
之类的东西,我不需要显示或编辑。这些关系似乎适用于应用程序的其余部分。
去掉这里无关紧要的字段和定义,我有:
class Quotation(db.Model):
__tablename__ = 'quotation'
id = db.Column(db.Integer, primary_key=True)
word = db.Column(db.String(50))
description = db.Column(db.Text)
created = db.Column(db.TIMESTAMP, default=db.func.now())
last_modified = db.Column(db.DateTime, server_default=db.func.now())
subject = db.relationship("QuotationSubject", back_populates="quotation")
def __str__(self):
return self.word
class Subject(db.Model):
__tablename__ = 'subject'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50))
created = db.Column(db.TIMESTAMP, default=db.func.now())
last_modified = db.Column(db.DateTime, server_default=db.func.now())
quotation = db.relationship("QuotationSubject", back_populates="subject")
def __str__(self):
return self.name
class QuotationSubject(db.Model):
__tablename__ = 'quotation_subject'
id = db.Column(db.Integer, primary_key=True)
quotation_id = db.Column(db.Integer, db.ForeignKey('quotation.id'), default=0, nullable=False)
subject_id = db.Column(db.Integer, db.ForeignKey('subject.id'), default=0, nullable=False)
created = db.Column(db.TIMESTAMP, default=db.func.now())
last_modified = db.Column(db.DateTime, server_default=db.func.now())
quotation = db.relationship('Quotation', back_populates='subject', lazy='joined')
subject = db.relationship('Subject', back_populates='quotation', lazy='joined')
在我的 admin.py
中,我只有:
class QuotationModelView(ModelView):
column_searchable_list = ['word', 'description']
form_excluded_columns = ['created', 'last_modified']
column_list = ('word', 'subject')
admin.add_view(QuotationModelView(Quotation, db.session))
就是这样。
在我的 list
视图中,我没有看到 subject
值,而是在 QuotationSubject
table 中看到相关条目,例如
test <QuotationSubject 1>, <QuotationSubject 17>, <QuotationSubject 18>
book <QuotationSubject 2>
同样,在我的 create
视图中,我没有从 QuotationSubject table 中得到一个包含十几个主题的列表,而是一个包含所有内容的巨大列表。
我看了一些 inline_models
的东西,这里的一些帖子建议,这也没有用,但无论如何还有其他帖子(例如 )建议我正在做的事情应该有效。如果有人能指出我做错了什么,我将不胜感激。
首先,我担心您的问题中缺少某些内容,因为我没有看到 Citation
class 的定义。但这似乎不是问题。
Flask 中多对多关系的最 classic 示例是用户的角色。以下是用户 M2M 关系的工作角色:
class RolesUsers(Base):
__tablename__ = 'roles_users'
id = db.Column(db.Integer(), primary_key=True)
user_id = db.Column(db.Integer(), db.ForeignKey('user.id'))
role_id = db.Column(db.Integer(), db.ForeignKey('role.id'))
class Role(RoleMixin, Base):
__tablename__ = 'role'
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(80), unique=True)
def __repr__(self):
return self.name
class User(UserMixin, Base):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(120), index=True, unique=True)
roles = db.relationship('Role', secondary='roles_users',
backref=db.backref('users', lazy='dynamic'))
在 Flask-Admin 中:
from user.models import User, Role
admin.add_view(PVCUserView(User, db.session))
admin.add_view(PVCModelView(Role, db.session))
请注意,关系只声明一次,backref
所以它是双向的。看起来你正在为此使用 back_populates
,.
对于您所描述的情况,看起来您的代码直接声明了与 M2M table 的关系。这真的是你想要的吗?您说您不需要访问 Flask-Admin 的 QuotationSubject table 中的额外列。但是你在其他地方需要它们吗?调用 quotation
或 subject
实际上 return QuotationSubject
的实例对我来说似乎很奇怪。我相信这就是 Flask-Admin 在创建视图中列出所有 QuotationSubject 行的原因。
所以我的建议是尝试将您的关系设置为直接指向目标模型 class,同时将 M2M table 作为 secondary
。
如果您想在其他地方访问关联模型(如果由于某种原因它确实不能成为 Association Proxy),则在每个模型中创建第二个关系 class 明确指向它。然后,您可能需要使用 form_excluded_columns
和 column_exclude_list
.
在 Flask-Admin 中排除该关系
我正在将 Flask-Admin 添加到现有的 Flask 应用程序中(使用 Python 3,以及 MySQL 和 SQLAlchemy),我根本不知道如何获得多对-许多关系才能正确呈现。我在这里阅读了很多关于此的问题,看起来我正在遵循正确的做法。
我有一个Quotation
table、一个Subject
table和一个QuotationSubject
table,必须是实际的class 而不是关联 table,但我不关心关联 table 中用于此目的的额外列;它们是 last_modified
之类的东西,我不需要显示或编辑。这些关系似乎适用于应用程序的其余部分。
去掉这里无关紧要的字段和定义,我有:
class Quotation(db.Model):
__tablename__ = 'quotation'
id = db.Column(db.Integer, primary_key=True)
word = db.Column(db.String(50))
description = db.Column(db.Text)
created = db.Column(db.TIMESTAMP, default=db.func.now())
last_modified = db.Column(db.DateTime, server_default=db.func.now())
subject = db.relationship("QuotationSubject", back_populates="quotation")
def __str__(self):
return self.word
class Subject(db.Model):
__tablename__ = 'subject'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50))
created = db.Column(db.TIMESTAMP, default=db.func.now())
last_modified = db.Column(db.DateTime, server_default=db.func.now())
quotation = db.relationship("QuotationSubject", back_populates="subject")
def __str__(self):
return self.name
class QuotationSubject(db.Model):
__tablename__ = 'quotation_subject'
id = db.Column(db.Integer, primary_key=True)
quotation_id = db.Column(db.Integer, db.ForeignKey('quotation.id'), default=0, nullable=False)
subject_id = db.Column(db.Integer, db.ForeignKey('subject.id'), default=0, nullable=False)
created = db.Column(db.TIMESTAMP, default=db.func.now())
last_modified = db.Column(db.DateTime, server_default=db.func.now())
quotation = db.relationship('Quotation', back_populates='subject', lazy='joined')
subject = db.relationship('Subject', back_populates='quotation', lazy='joined')
在我的 admin.py
中,我只有:
class QuotationModelView(ModelView):
column_searchable_list = ['word', 'description']
form_excluded_columns = ['created', 'last_modified']
column_list = ('word', 'subject')
admin.add_view(QuotationModelView(Quotation, db.session))
就是这样。
在我的 list
视图中,我没有看到 subject
值,而是在 QuotationSubject
table 中看到相关条目,例如
test <QuotationSubject 1>, <QuotationSubject 17>, <QuotationSubject 18>
book <QuotationSubject 2>
同样,在我的 create
视图中,我没有从 QuotationSubject table 中得到一个包含十几个主题的列表,而是一个包含所有内容的巨大列表。
我看了一些 inline_models
的东西,这里的一些帖子建议,这也没有用,但无论如何还有其他帖子(例如
首先,我担心您的问题中缺少某些内容,因为我没有看到 Citation
class 的定义。但这似乎不是问题。
Flask 中多对多关系的最 classic 示例是用户的角色。以下是用户 M2M 关系的工作角色:
class RolesUsers(Base):
__tablename__ = 'roles_users'
id = db.Column(db.Integer(), primary_key=True)
user_id = db.Column(db.Integer(), db.ForeignKey('user.id'))
role_id = db.Column(db.Integer(), db.ForeignKey('role.id'))
class Role(RoleMixin, Base):
__tablename__ = 'role'
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(80), unique=True)
def __repr__(self):
return self.name
class User(UserMixin, Base):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(120), index=True, unique=True)
roles = db.relationship('Role', secondary='roles_users',
backref=db.backref('users', lazy='dynamic'))
在 Flask-Admin 中:
from user.models import User, Role
admin.add_view(PVCUserView(User, db.session))
admin.add_view(PVCModelView(Role, db.session))
请注意,关系只声明一次,backref
所以它是双向的。看起来你正在为此使用 back_populates
,
对于您所描述的情况,看起来您的代码直接声明了与 M2M table 的关系。这真的是你想要的吗?您说您不需要访问 Flask-Admin 的 QuotationSubject table 中的额外列。但是你在其他地方需要它们吗?调用 quotation
或 subject
实际上 return QuotationSubject
的实例对我来说似乎很奇怪。我相信这就是 Flask-Admin 在创建视图中列出所有 QuotationSubject 行的原因。
所以我的建议是尝试将您的关系设置为直接指向目标模型 class,同时将 M2M table 作为 secondary
。
如果您想在其他地方访问关联模型(如果由于某种原因它确实不能成为 Association Proxy),则在每个模型中创建第二个关系 class 明确指向它。然后,您可能需要使用 form_excluded_columns
和 column_exclude_list
.