python - SQLAlchemy 关系:查找具有一个或多个共同属性的实例
问题描述
我不知道如何表达这个问题,因为我不知道我想要达到的目标的术语(mods,请随时提出改进建议)。
我有两种类型的用户,Student
和Instructor
. 两者都可以有一个或多个Tag
s,它们基本上是一种流派(摇滚、放克等)。为了与一个关联Student
,Instructor
我Tag
有一个关联表。
我有最后一个模型,Lesson
它有Student
和的 ID Instructor
。在创建 aLesson
时,仅设置这些 ID 中的一个,具体取决于它是它Student
还是Instructor
创建它的 an。如果 aStudent
创建 a Lesson
,我需要找到所有Instructor
与 s 有一个或多个Tag
s 的 s Student
。我该如何实现这一目标?我对数据库关系的了解有限,因此不胜感激!
这是模型的代码:
class Instructor(db.Model):
id = db.Column(db.Integer, primary_key=True)
genres = db.relationship("Tag", secondary=instructor_tag_association_table, backref=db.backref("instructors", lazy="dynamic"))
class Student(db.Model):
id = db.Column(db.Integer, primary_key=True)
genres = db.relationship("Tag", secondary=student_tag_association_table, backref=db.backref("students", lazy="dynamic"))
class Tag(db.Model):
id = db.Column(db.Integer, primary_key=True)
genre = db.Column(db.String)
class Lesson(db.Model):
id = db.Column(db.Integer, primary_key=True)
instructor_id = db.Column(db.Integer, db.ForeignKey("instructor.id"))
student_id = db.Column(db.Integer, db.ForeignKey("student.id"))
# Association tables
instructor_tag_association_table = db.Table(
"instructor_tags",
db.Column("instructor_id", db.Integer, db.ForeignKey("instructor.id")),
db.Column("tag_id", db.Integer, db.ForeignKey("tag.id")),
)
student_tag_association_table = db.Table(
"student_tags",
db.Column("student_id", db.Integer, db.ForeignKey("student.id")),
db.Column("tag_id", db.Integer, db.ForeignKey("tag.id")),
)
我知道这在几个层面上都是错误的,但是说我有一个单一的 ID Instructor
,然后我正在寻找这样的查询来寻找教训:
instructor_id = 1
instructor = Instructor.query.filter_by(id=instructor_id).first()
eligible_lessons = Lesson.query.filter(Lesson.student_id.has("genre in instructor.genre"))
解决方案
我的回答受到了这个启发。
如果我的解释正确,我认为问题的症结在于您正在寻找有学生但没有指定教师的课程,该课程的学生genres
和教师的genres
.
我在您的模型上添加了student
关系instructor
以Lesson
补充Foreign Keys
您已经创建的模型,这使我更容易生成一些测试数据,如果没有别的:
class Lesson(db.Model):
id = db.Column(db.Integer, primary_key=True)
instructor_id = db.Column(db.Integer, db.ForeignKey("instructor.id"))
student_id = db.Column(db.Integer, db.ForeignKey("student.id"))
student = db.relationship(Student, uselist=False, backref='lessons')
instructor = db.relationship(Instructor, uselist=False, backref='lessons')
这是我生成的测试数据:
import random
db.drop_all()
db.create_all()
# create a set of tags
tags = [Tag(genre=g) for g in ('Jazz', 'Funk', 'Rock', 'Classical', 'Metal')]
# create 10 students with 2 tags randomly assigned
students = [Student(genres=random.sample(tags, 2)) for _ in range(10)]
# create 2 instructors with 2 tags randomly assigned
instructors = [Instructor(genres=random.sample(tags, 2)) for _ in range(2)]
# create a lesson for each student
lessons = [Lesson(student=s) for s in students]
db.session.add_all(tags + students + instructors + lessons)
db.session.commit()
然后对于查询,我查询Lesson
join on Student
,student_tag_association_table
以便我可以找到与其中一个链接匹配的Lesson
withinstructor_id == None
和 a Student
with a :tag_id
Instructor's
tag_ids
# randomly select an instructor
instructor = random.choice(instructors)
possible_lessons = db.session.query(Lesson).\
join(Student).\
join(student_tag_association_table).\
filter(and_(Lesson.instructor_id == None,
or_(
student_tag_association_table.c.tag_id.in_(
g.id for g in instructor.genres
)
)
)).all()
然后进行测试:
for lesson in possible_lessons:
try:
assert any([g in lesson.student.genres for g in instructor.genres])
except AssertionError:
print('uh oh')
else:
print('yes')
# yes
# yes
# yes
# yes
# yes
由于测试数据是随机的,因此您每次都会得到不同数量的yes
输出。
推荐阅读
- google-apps-script - 如何获取要访问的特定选项卡
- ruby-on-rails - Ruby Rails 标记 - 与 3 个表的多对多关系 - 在中间(通过)表双行
- c# - 如何获取 userManager.VerifyUserTokenAsync 的目的字段?
- linux - git grep 和 OR'd 多个带有管道的子句?
- python - 如何在不更改索引并返回先前操作的所有列的情况下旋转数据框
- python - 用于灰度图像的预训练对象检测 API 模型(1 通道)
- c++ - 从 json 文本中删除回车
- python - 无法从 numPyy 数组制作视频
- fonts - 通过 Heroku CLI 列出系统字体
- javascript - 我的页面上有一堆具有不同参考 URL 的锚标记。如何使用 queryselectorAll 选择标签子集?