【问题标题】:Django: Filter in multiple models linked via ForeignKey?Django:过滤通过ForeignKey链接的多个模型?
【发布时间】:2012-11-22 15:35:48
【问题描述】:

我想为以下值和模型创建一个过滤排序混合:

class Course(models.Model):
    title = models.CharField(max_length=70)
    description = models.TextField()
    max_students = models.IntegerField()
    min_students = models.IntegerField()
    is_live = models.BooleanField(default=False)
    is_deleted = models.BooleanField(default=False)
    teacher = models.ForeignKey(User)

class Session(models.Model):
    course = models.ForeignKey(Course)
    title = models.CharField(max_length=50)
    description = models.TextField(max_length=1000, default='')
    date_from = models.DateField()
    date_to = models.DateField()
    time_from = models.TimeField()
    time_to = models.TimeField()

class CourseSignup(models.Model):
    course = models.ForeignKey(Course)
    student = models.ForeignKey(User)
    enrollment_date = models.DateTimeField(auto_now=True)

class TeacherRating(models.Model):
    course = models.ForeignKey(Course)
    teacher = models.ForeignKey(User)
    rated_by = models.ForeignKey(User)
    rating = models.IntegerField(default=0)
    comment = models.CharField(max_length=300, default='')
  • 课程可以是“离散数学 1”
  • 课程是与课程相关的单独课程(例如 1. 简介、2. 第 I 章、3 期末考试等)以及日期/时间
  • CourseSignup 是学生的“注册”
  • TeacherRating 跟踪学生对教师的评分(课程完成后)

我想实现以下功能

  • 按日期(最早的 Session.date_from)、Course.Name 排序(asc、desc)
  • 筛选依据:日期(最早的 Session.date_from 和最后 Session.date_to)、平均 TeacherRating(例如最小值 = 3)、CourseSignups(例如最少 5 个用户注册) (这些选项通过 GET 参数传递,例如 sort=date_ascending&f_min_date=10.10.12&...)

您将如何为此创建函数?

我尝试过使用

  • 非规范化(只是在 Course 中添加了一个字段以获取所需的过滤/排序标准,并在发生更改时对其进行更新),但我对此不太满意(例如,每次 TeacherRating 后都需要大量更新)。
  • ForeignKey 查询 (Course.objects.filter(session__date_from=xxx)),但我稍后可能会遇到性能问题..

感谢任何提示!

【问题讨论】:

    标签: django django-models django-queryset


    【解决方案1】:

    除了将 Q 对象用于高级 AND/OR 查询之外,还要熟悉反向查找。

    当 Django 为外键关系创建反向查找时。在您的情况下,您可以获得属于课程的所有会话,这是两种方式之一,每种方式都可以过滤。

    c = Course.objects.get(id=1)
    sessions = Session.objects.filter(course__id=c.id) # First way, forward lookup.
    sessions = c.session_set.all() # Second way using the reverse lookup session_set added to Course object.
    

    您还需要熟悉annotate()aggregate(),它们允许您计算字段并对结果进行排序/过滤。例如,Count、Sum、Avg、Min、Max 等。

    courses_with_at_least_five_students = Course.objects.annotate(
        num_students=Count('coursesignup_set__all')
    ).order_by(
        '-num_students'
    ).filter(
        num_students__gte=5
    )
    
    
    course_earliest_session_within_last_240_days_with_avg_teacher_rating_below_4 = Course.objects.annotate(
        min_session_date_from = Min('session_set__all')
    ).annotate(
        avg_teacher_rating = Avg('teacherrating_set__all')
    ).order_by(
        'min_session_date_from',
        '-avg_teacher_rating'
    ).filter(
        min_session_date_from__gte=datetime.now() - datetime.timedelta(days=240)
        avg_teacher_rating__lte=4
    )
    

    Q 用于允许您在查询中进行逻辑 AND 和逻辑 OR。

    【讨论】:

    • 感谢您提供非常详细的回答 - 对我有很大帮助!干杯
    【解决方案2】:

    我建议你看看复杂的查找:https://docs.djangoproject.com/en/1.5/topics/db/queries/#complex-lookups-with-q-objects

    以下查询可能不适用于您的情况(教师模型是什么样的?),但我希望它可以作为如何使用复杂查找的指示。

    from django.db.models import Q
    
    Course.objects.filter(Q(session__date__range=(start,end)) &
                          Q(teacher__rating__gt=3))
    

    除非绝对必要,否则我确实会避开非规范化。

    我对你的排序问题并不完全清楚。您想显示按 date_from 过滤的课程,并按日期、名称排序吗?

    【讨论】:

    • 感谢您的更新,马克!当我想检查时,我忘了提及这个案例。有多少学生签署了课程并对此进行过滤。 Q Objects 还在继续吗?性能如何(与非规范化相比)?
    猜你喜欢
    • 2021-05-26
    • 2020-01-19
    • 1970-01-01
    • 2019-06-13
    • 2023-03-22
    • 2010-09-20
    • 2011-10-12
    • 2018-09-29
    相关资源
    最近更新 更多