如何查询以便显示每个实例的字段而不是实际实例

Posted

技术标签:

【中文标题】如何查询以便显示每个实例的字段而不是实际实例【英文标题】:How to query so that a field of each instance will show up instead of the actual instance 【发布时间】:2021-10-16 12:21:04 【问题描述】:

我正在尝试查询,以便每个模型实例中的字段值都不会重复显示。所有这些都发生在表单中:

class OrganisorClassStatusUpdateForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(OrganisorClassStatusUpdateForm, self).__init__(*args, **kwargs)
        self.fields['off_day_student'] = forms.ModelChoiceField(
            queryset= Class.objects.filter(teacher=self.instance.teacher).filter(is_new_set=True).filter(time=self.instance.time).order_by('-date')[:10]
        )

这里,self.instance 指的是我正在使用此表单更新的Class 模型实例。但是,使用此代码,我将收到一个表单字段的Class 实例列表。我想要的是一个Student 列表,对应于表单字段中的每个Class 实例(每个班级只有一个学生)。因此,我想要 Student1、Student2、Student3 而不是 Class1、Class2、Class3。此外,如果学生姓名有任何重复,我只想显示一个。我希望学生们也按-date的顺序列出上面代码所示的课程。请问我任何问题。非常感谢。

这是你们中的一些人所问的类模型:

class Class(models.Model):
    teacher = models.ForeignKey('Agent', null=True, blank=True, on_delete=models.SET_NULL)
    student = models.ForeignKey('Lead', null=True, blank=True, on_delete=models.SET_NULL, related_name='student')

【问题讨论】:

您需要从Teacher 模型而不是Class 模型构建您的查询集,并根据它们是否与某个类相关联(以及您需要的任何其他条件)进行过滤。 请分享您的模型。 @michjnich 不幸的是,我在Class 模型中使用了一个外键来指向Teacher 模型,这意味着我无法从老师那里查询课程。 @WillemVanOnsem 我为Class 添加了模型。 Teacher(或“代理”)中没有将其链接到 Class 的字段。 您可以从老师那里链接回班级设置:docs.djangoproject.com/en/3.2/ref/models/relations/… 【参考方案1】:

您可以使用:

Teacher.objects.filter(
    class__student=self.instance.student,
    class__is_new_set=True,
    class__time=self.instance.time,
).order_by('-class__date').distinct()[:10]

如果你定义了从ClassTeacher 的关系,那么 Django 会反向添加一个概念关系。您可以使用related_query_name=… [Django-doc] 或related_name=… parameter [Django-doc] 指定该关系的名称。默认情况下,related_query_name 字段是类的小写名称。

如果您只想一次检索每个Teacher 对象,则不能使用.order_by('-class__date'),因为这将执行没有GROUP BY 子句的JOIN

在这种情况下,您可以例如订购最小的class__date,例如:

from django.db.models import Min

Teacher.objects.filter(
    class__student=self.instance.student,
    class__is_new_set=True,
    class__time=self.instance.time,
).alias(
    min_date=Min('class_date')
).order_by('-min_date').distinct()[:10]

或在django-3.2之前:

from django.db.models import Min

Teacher.objects.filter(
    class__student=self.instance.student,
    class__is_new_set=True,
    class__time=self.instance.time,
).annotate(
    min_date=Min('class__date')
).order_by('-min_date').distinct()[:10]

或者如果你想要学生:

from django.db.models import Min

Student.objects.filter(
    student__student=self.instance.student,
    student__is_new_set=True,
    student__time=self.instance.time,
).annotate(
    min_date=Min('student__date')
).order_by('-min_date').distinct()[:10]

我们在这里使用student__ 的原因是因为您的关系中的related_name='student'ClassLead。然而,这没有多大意义。与以下合作可能会更好:

class Class(models.Model):
    teacher = models.ForeignKey('Agent', null=True, blank=True, on_delete=models.SET_NULL)
    student = models.ForeignKey('Lead', null=True, blank=True, on_delete=models.SET_NULL, related_name='classes')

然后查询:

from django.db.models import Min

Student.objects.filter(
    classes__student=self.instance.student,
    classes__student__is_new_set=True,
    classes__student__time=self.instance.time,
).annotate(
    min_date=Min('classes__date')
).order_by('-min_date').distinct()[:10]

【讨论】:

感谢您的评论。实际上,我编辑了您的回复,以便获得像 Lead.objects.filter(student__teacher=self.instance.teacher, student__is_new_set=True, student__time=self.instance.time,).order_by('-student__date').distinct()[:10] 这样的学生列表(而不是教师列表)。但是,我仍然在我的表单列表中得到同一个学生的多个结果。我不知道为什么会这样,因为代码中包含distinct()。有什么办法可以解决这个问题吗?我想这将是这个问题的终结。 @codebuilder: 那是因为-class_date,如果你只想要老师,你应该删除.order_by('...')子句,或者替换它,例如用class__datesl的最小值 @codebuilder: 然后你使用Student.objects,因为从Class到学生的related_name=...被命名为student(这没什么意义),我们用@查询987654353@,见编辑。 @codebuilder:在这种情况下,您查询的是“同学”,而不是班级的老师。 好的。我认为它现在正在工作。感谢到目前为止。但是,为什么我在提交显示Cannot filter a query once a slice has been taken. 的表单时会收到错误消息?【参考方案2】:

如果教师是 Class 模型中的一个字段,你可以说:

ids = Class.objects.filter(student=self.object.student).order_by('-date').values_list("teacher", flat=True).distinct()[:10] 
queryset = Teacher.objects.filter(pk__in=ids)

这是Queryset.values() 的文档:https://docs.djangoproject.com/en/3.2/ref/models/querysets/#django.db.models.query.QuerySet.values 请注意:当将 values() 与 distinct() 一起使用时,请注意排序会影响结果。有关详细信息,请参阅 distinct() 中的注释。 (来自文档) 似乎有办法解决这个问题。请阅读本文档页面中的注释部分:https://docs.djangoproject.com/en/3.2/ref/models/querysets/#django.db.models.query.QuerySet.distinct

【讨论】:

我试过了,但我收到了一个奇怪的列表,比如每个班级实例的 'teacher':1。 ids = Class.objects.filter(student=self.object.student).order_by('-date').values_list("teacher", flat=True).distinct()[:10] queryset = Teacher.objects.filter(pk__in=ids) 这可能不是最好的选择,但可能会奏效。最后,它做了两个查询。第一个获取教师的 PK,第二个用这些 PK 查询教师。 我认为这是迄今为止最好的答案,谢谢。我不知道为什么,但它似乎工作。但是,我的教师名单似乎不是按照课程的-date 的顺序排列的。有什么办法可以做到吗? 是的,抱歉,我读到过但忘了提及。在文档中有关于 ordering 和 distinct() 冲突的警告。我将很快编辑我的答案。请看一下。 需要注意的一点是,我刚刚完全编辑了我的问题,因为我很难与其他用户交流这个过于简化的实际代码版本。我认为同样的逻辑也适用。我使用了你之前的代码逻辑来挖掘,它就像你说的那样工作(除了订购部分)。我只是想让你知道问题现在是我的实际代码。

以上是关于如何查询以便显示每个实例的字段而不是实际实例的主要内容,如果未能解决你的问题,请参考以下文章

mysql中的分组统计函数及其用法实例

Snowflake 我们如何在字段数组上运行非透视查询而不是显式声明每个字段?

为啥私有字段是类型私有的,而不是实例私有的?

jQuery触发嵌套表单rails cocoon上的所有实例

如何让pyspark显示整个查询计划而不是......如果有很多字段?

仅将 java 类实例转换为原始类型