如何在Flask/SQLAlchemy中显示多对多查询结果的列
我正在学习Python/Flask/SQLAlchemy,想通过建立一个简单的维基百科来练习(这个维基百科主要参考了一个Flask-Admin的例子),但是我在理解如何显示我多对多关系中的新列时遇到了困难。
我已经成功创建了维基,并且为标签建立了一个多对多关系表,这个过程没有问题(根据我看到的,标签功能也正常),但我想把标签显示为一列,却一直搞不定逻辑。
目标:我想显示一列,里面展示多对多关联表中引用的标签。
下面是我想实现的效果的图片:
这是我认为相关的代码:
wiki_tags_table = db.Table('wiki_tags', db.Model.metadata,
db.Column('wiki_id', db.Integer, db.ForeignKey('wiki.id')),
db.Column('tag_id', db.Integer, db.ForeignKey('tag.id'))
)
class Wiki(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), unique=True)
description = db.Column(db.Text)
path = db.Column(db.Unicode(256))
date_added = db.Column(db.DateTime)
tags_id = db.Column(db.Integer, db.ForeignKey('tag.id'))
tags = db.relationship('Tag', secondary=wiki_tags_table, backref=db.backref('wiki_tags_table', lazy='dynamic'))
def __unicode__(self):
return self.item
class WikiAdmin(sqla.ModelView):
column_exclude_list = ['path']
column_hide_backrefs = False
form_overrides = {
'path': form.FileUploadField
}
form_args = {
'path': {
'label': 'File',
'base_path': file_path
}
}
column_searchable_list = ('title', 'description', 'path')
def __init__(self, session):
super(WikiAdmin, self).__init__(Wiki, session)
class Tag(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Unicode(64))
def __unicode__(self):
return self.name
我一直在参考这些文档(主要是尝试backref的不同变体),但还没有找到解决办法:
4 个回答
0
试试我做的这个方法,给多对多的字段使用一个特别的列格式化器。这对我来说是有效的。
def many_to_many_formatter(view, context, model, name: str) -> str:
"""This function formats the many-to-many fields for display in the list view"""
try:
rel_field, col_name = name.split(".")
list_of_tags: list = getattr(model, rel_field)
list_of_results: list = [str(getattr(tag, col_name)) for tag in list_of_tags]
new_str: str = ", ".join(list_of_results)
except Exception:
current_app.logger.exception("Error trying to format many-to-many relationship field in list view!")
new_str = ""
return new_str
class SpecialView(ModelView):
"""Flask-Admin view"""
column_list = (
"model",
"description",
# many-to-many field
"parts_rel.part_num"
)
column_formatters = {
"parts_rel.part_num": many_to_many_formatter,
}
0
我刚才也遇到了同样的问题,解决办法就是在ViewModel类里添加一个column_list字段,所以在这个情况下,代码是这样的:
class WikiAdmin(sqla.ModelView):
...
column_list = ('title', 'description', 'dataadded', 'tags')
这个问题虽然是老问题,但这是我在自己寻找解决办法时遇到的第一个(也可以说是唯一相关的)讨论,所以希望这个回答能帮到某个人,节省一些时间。
0
关系属性会把相关的表加载成一个对象列表,所以你可以在视图中像这样打印出所有的维基条目和所有相关的标签:
for wiki_item in Wiki.query.all():
print wiki_item.title
for tag in wiki_item.tags:
print tag.name
如果你这样做,会发生什么呢?
1
我不确定这是否有帮助,因为我自己也在学习。不过我遇到过类似的问题,我想从一个“外键表”中显示一列数据,最后是这样做的:
我的 modle.py 文件
from app import db
class Member(db.Model):
__tablename__ = 'members'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(64), index=True)
phone = db.Column(db.String(10), index=True)
email = db.Column(db.String(120), index=True, unique=True)
grade = db.relationship('Grade', backref='member')
attendance = db.relationship('Attendance', backref='member')
def __repr__(self):
return '<User %r>' % self.name
class Grade(db.Model):
__tablename__ = 'grades'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
member_id = db.Column(db.Integer, db.ForeignKey('members.id'))
grade = db.Column(db.String(10))
grade_date = db.Column(db.Date)
def __repr__(self):
return '<Grading %r>' % self.id
def __str__(self):
return self.grade
def __unicode__(self):
return self.grade
class Attendance(db.Model):
__tablename__ = 'attendance'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
id_member = db.Column(db.Integer, db.ForeignKey('members.id'))
attend_date = db.Column(db.Date)
def __repr__(self):
return '<Attenance %r>' % self.id
我的 views.py 文件
from app.models import Member, Grade, Attendance
from app import app, admin, db
from flask_admin import BaseView, expose
from flask_admin.contrib.fileadmin import FileAdmin
from flask_admin.contrib.sqla import ModelView
import os.path as op
class AdminView(ModelView):
column_display_pk = True # optional, but I like to see the IDs in the list
column_hide_backrefs = False
# column_list = ('id', 'name', 'parent')
create_modal = True
edit_modal = True
class MemberAdmin(ModelView):
column_display_pk = True # optional, but I like to see the IDs in the list
column_hide_backrefs = False
can_view_details = True
create_modal = True
edit_modal = True
form_columns = ['name', 'phone', 'email', 'grade', 'attendance']
column_details_list = ['name', 'phone', 'email', 'grade', 'attendance']
column_searchable_list = ['name', 'email']
column_list = ('id', 'name', 'phone','email','grade')
class GradeAdmin(ModelView):
column_display_pk = True # optional, but I like to see the IDs in the list
column_hide_backrefs = False
column_list = ('id', 'member', 'grade', 'grade_date')
form_choices = {'grade': [('Beginner', 'Beginner'), ('Yellow', 'Yellow'), ('Orange', 'Orange'),
('Green 1', 'Green 1'), ('Green 2', 'Green 2'), ('Blue 1', 'Blue 1'),
('Blue 2', 'Blue 2'), ('Purple 1', 'Purple 1'), ('Purple 2', 'Purple 2'),
('Brown 1', 'Brown 1'), ('Brown 2', 'Brown 2'), ('Red 1', 'Red 1')]}
admin.add_view(MemberAdmin(Member, db.session, endpoint='member', category='Admin'))
admin.add_view(GradeAdmin(Grade, db.session, endpoint='grades', category='Admin'))
admin.add_view(ModelView(Attendance, db.session, endpoint='attendance', category='Admin'))
由于我还不是很懂这些(还在学习中),我觉得让我在 Member 模型中看到额外一列(来自 Grade 模型)的关键在于 MemberAdmin 类中的这些代码:
column_hide_backrefs = False
can_view_details = True
...
form_columns = ['name', 'phone', 'email', 'grade', 'attendance']