Python中flask-sqlalchemy多对多关联如何定义与查询?使用第三张表时可能存在的错误
背景:一个主题可以对应多个产品,一个产品可以属于多个主题
我也不想使用第三张表,但是人家已经给我了 sql 文件,我只能使用,要不怎么读取人家的数据
- 中间表
class Theme_Product(db.Model):
__tablename__ = 'theme_product'
theme_id=db.Column(db.Integer,db.ForeignKey('theme.id'), primary_key=True)
product_id=db.Column(db.Integer,db.ForeignKey('product.id'), primary_key=True)
- 主题表简化
class Theme(db.Model):
__tablename__ = 'theme'
id = db.Column(db.Integer, primary_key=True)
productInTheme=db.relationship('Theme_Product',
foreign_keys=[Theme_Product.theme_id],
backref=db.backref('backTheme',lazy='joined'),
lazy='dynamic',
cascade='all,delete-orphan')
- 产品表
class Product(db.Model):
__tablename__ = 'product'
id = db.Column(db.Integer, primary_key=True)
theme=db.relationship('Theme_Product',
foreign_keys=[Theme_Product.product_id],
backref=db.backref('backProduct', lazy='joined'),
lazy='dynamic',
cascade='all,delete-orphan')
- 查询语句
- 从 theme 查询其下属包含的所有 product
- 导入 Theme 类
Theme.query.get(id).productInTheme- 此时提示<class 'sqlalchemy.orm.dynamic.AppenderBaseQuery'>
- Theme.query.get(id).productInTheme
- 无法错误提示很乱,感觉像是 id 相互对应不上什么的
-----------------------跪求指点,如何查询--------------------------------
Python中flask-sqlalchemy多对多关联如何定义与查询?使用第三张表时可能存在的错误
<br>tags = db.Table('article_tag',<br> db.Column('article_id', db.Integer(), db.ForeignKey('<a target="_blank" href="http://article.id" rel="nofollow noopener">article.id</a>')),<br> db.Column('tag_id', db.Integer(), db.ForeignKey('<a target="_blank" href="http://tag.id" rel="nofollow noopener">tag.id</a>')))<br><br><br>class Article(db.Model):<br> id = db.Column(db.Integer(), primary_key=True)<br> title = db.Column(db.String(255))<br> text = db.Column(db.Text())<br> publish_time = db.Column(db.DateTime(), default=datetime.datetime.utcnow)<br> comments = db.relationship("Comment", backref='article', lazy='dynamic')<br> tags = db.relationship('Tag',<br> secondary=tags,<br> backref=db.backref('article', lazy='dynamic'))<br><br> def json(self):<br> return dict(<br> id=<a target="_blank" href="http://self.id" rel="nofollow noopener">self.id</a>,<br> title=self.title,<br> text=self.text,<br> publish_time=utc_local(self.publish_time),<br> username=self.user.username,<br> tags=[<a target="_blank" href="http://tag.name" rel="nofollow noopener">tag.name</a> for tag in self.tags]<br> )<br><br> def __str__(self):<br> return "<Article {}>".format(self.title)<br><br> def __repr__(self):<br> return "<Article {}>".format(self.title)<br><br><br>class Tag(db.Model):<br> id = db.Column(db.Integer(), primary_key=True)<br> name = db.Column(db.String(255))<br><br> def __str__(self):<br> return "<Tag {}>".format(<a target="_blank" href="http://self.name" rel="nofollow noopener">self.name</a>)<br><br> def __repr__(self):<br> return "<Tag {}>".format(<a target="_blank" href="http://self.name" rel="nofollow noopener">self.name</a>)<br>
帖子回复:
这个问题很典型。Flask-SQLAlchemy中定义多对多关系,用db.Table创建关联表,然后在模型里用relationship和secondary参数关联。直接上代码:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
# 先定义关联表(必须放在模型类前面)
association_table = db.Table('association',
db.Column('student_id', db.Integer, db.ForeignKey('student.id')),
db.Column('course_id', db.Integer, db.ForeignKey('course.id'))
)
class Student(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50))
# 多对多关系
courses = db.relationship('Course',
secondary=association_table,
backref=db.backref('students', lazy='dynamic'),
lazy='dynamic')
class Course(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100))
查询操作:
# 添加关联
student = Student.query.get(1)
course = Course.query.get(1)
student.courses.append(course)
db.session.commit()
# 查询学生选的所有课
student = Student.query.get(1)
for course in student.courses:
print(course.name)
# 查询选了某课的所有学生
course = Course.query.get(1)
for student in course.students:
print(student.name)
# 动态查询(比如筛选)
student = Student.query.get(1)
math_courses = student.courses.filter(Course.name.like('%Math%')).all()
常见错误:
- 关联表定义顺序:关联表必须在引用它的模型类之前定义。
- 重复定义backref:两边都用
relationship会导致冲突,一边用backref就行。 - 懒加载模式:
lazy='dynamic'返回查询对象而不是列表,方便进一步过滤。 - 表名冲突:确保关联表的
db.Table第一个参数(表名)在数据库中是唯一的。 - 外键引用:
ForeignKey里的字符串是表名.字段名,注意表名是数据库里的实际表名(默认是类名小写)。
总结建议: 关联表放模型前面,一边用backref,注意表名别冲突。
这样定义,第三张表的数据怎么用?这样数据只能从零开始吧
看 1 楼代码的 relationship 的定义. 就是用那个去使用

