创建一个左Django中加入空值

问题描述 投票:1回答:2

我试图创造一个Django相当于SQL LEFT OUTER JOIN的。但是我有这个麻烦。

class Course(models.Model):
    name = models.CharField(max_length=255)

class Grades(models.Model):
    grade = models.CharField(max_length=3)
    student = models.ForeignKey(Student, on_delete=models.CASCADE)
    course = models.ForeignKey(Course, on_delete=models.CASCADE)

我的目标是什么,是要遍历所有的课程,当有对学生(我已经有)的值,然后打印出他/她的品位。这似乎很容易给我,但我只是不出来...

编辑:

多一点解释:我只是有学生证,这就是我的意思是由我已经有了。我需要在表格中打印出所有的课程(这是在模板)

所以,你会得到:

英语 - 8.0 法国 - 德文 - 10

因此,在这种情况下,没有等级被定为法国,为此无级将被显示。

python django python-3.x django-models
2个回答
1
投票

您可以通过使用prefetch_related与受限制的queryset做到这一点。

from django.db.models import Prefetch
courses = Course.objects.prefetch_related(
    Prefetch('grades_set', queryset=Grade.objects.filter(student=my_student))
)

现在,当你遍历课程,course.grade_set.all()将只包含对my_student相关等级。


1
投票

你想要的是在Course子查询注释。

你有N:GradesCourse之间的关系1,这意味着,有可能是0到一个Grades返回ñCourse实例。这仍然是从DB的角度真实的,即使你把它降低到一个学生的课程。

业务逻辑可能说,你只能有每门课程和学生一个年级,但你必须对您的数据库没有这样的限制(你可以添加一个unique_together = ['course', 'student']),但你可能仍然需要保持这个事实考虑的注释。

from django.db.models import OuterRef, Subquery, Max

# student => which you already have
# Max() added because the subquery must ever only return 1 hit
# otherwise an error is raised
grade_query = Grades.objects.filter(course=OuterRef('pk'), student=student).annotate(
    max_grade=Max('grade')).values('max_grade')
Course.objects.annotate(
    student_grade=Subquery(grade_query, output_field=CharField())
).values('name', 'student_grade')

文档:https://docs.djangoproject.com/en/2.1/ref/models/expressions/#subquery-expressions


SQL语句/性能

有多少SQL语句的说明是根据,因为评论的解决方案触发。

Plain ORM

for course in Course.objects.all():
    grade = course.grades_set.filter(student=student).first() or ''
    print(f'{course.name}: {grade}')

这导致:

  • 1个查询所有课程对象
  • +1每门课程对象为这个学生,该课程取成绩

产品总数,如果有20门课程,这将导致21种SQL选择。

Prefetch Related

更改Course.objects.all()丹尼尔·罗斯曼的建议(非常好!):

Course.objects.prefetch_related(
    Prefetch('grades_set', queryset=Grade.objects.filter(student=my_student))
)

结果在2种SQL选择:

  • 1课程
  • 1为所有年级的所有课程,这个特定学生

ORM层负责合并这两个查询的结果。

(好多了,最灵活的解决方案。)

Annotate/Aggregation

结果正好1 SQL选择。

你需要知道你事先想要的东西,如果性能是一个问题,你想避免额外的SQL选择不惜一切代价,values()使得那肯定,因为它不会产生任何型号的实例,但简单的值,并且只选择这些人恰恰是值,而不是其他任何东西(如多个相关模型,引发不必要的连接)。

如果结果只需要在显示模板,在视图中获取,而不是意为别的,这是一个不错的选择。

© www.soinside.com 2019 - 2024. All rights reserved.