Django - 查询:使用相关模型字段注释查询集

Posted

技术标签:

【中文标题】Django - 查询:使用相关模型字段注释查询集【英文标题】:Django - Query : Annotate Queryset with Related Model fields 【发布时间】:2020-07-31 06:16:45 【问题描述】:

我在 Django 中使用 PostgreSQL 有以下 Schema。

Class Person (models.Model):
    name = models.CharField(max_length=255)
    email= models.CharField(max_legth = 255)
    created_at = models.DateTimeField()

Class PersonTask(models.Model):
   person = models.ForeignKey(Person)
   title = models.TextField()
   created_at = models.DateTimeField()

Class PersonHistory(models.Model):
   person = models.ForeignKey(Person)
   note = models.TextField()
   created_at = models.DateTimeField()

现在我需要查询数据库,比如最新PersonTask__titlemax_task 和最新PersonHistory__notemax_note 的 Person 的所有值

例如:

<Queryset: [
name: "abc" ,email:"abc@gmail.com",created_at :"2019-01-02", max_task:"This is my latest tasktitle" , max_note: "This is my latest history note",
name: "abcd" ,email:"abcd@gmail.com",created_at :"2019-03-02", max_task:"This is my latest tasktitle for abcd" , max_note: "This is my latest history note for abcd"
]>

但是,我最多可以得到最新任务和最新历史的 id

Person.objects.filter(customer_id= 1).\
               annotate( max_task = Max('persontask')).\
               annotate(max_note = Max('personhistory')).\
               order_by('-id')

或使用以下查询的随机任务或注释文本

Person.objects.filter(customer_id= 1).\
               annotate( max_task = Max('persontask__title')).\
               annotate(max_note = Max('personhistory__note')).\
               order_by('-id')

如何解决这个问题??

【问题讨论】:

【参考方案1】:

由于您没有提到这些模型之间的 ForeignKeys,我怀疑 Task 和 History 在名为 person 的字段中对 Person 具有 FK。

我会使用 Subquery 和 OuterRef 的组合来处理这个查询

from django.db.models import OuterRef, Subquery

result = (
    Person.objects
        .filter(customer_id=1)
        .annotate(
            task_title=Subquery(Task.objects.filter(person=OuterRef('pk')).order_by('-created_at').values('title')[:1]),
            history_note=Subquery(HistoryNote.objects.filter(person=OuterRef('pk')).order_by('-created_at').values('note')[:1])
        )
        .order_by('-id')
)

【讨论】:

是的,您对数据库模型的看法是正确的。我已经更新了模型。但是我可以知道,哪个版本的 Django 会支持这个? 我查看了 django 文档,它看起来甚至在 1.11 中也受支持 :-) docs.djangoproject.com/en/1.11/ref/models/expressions/… 非常感谢。是的,我已经尝试过并且工作正常 我做到了:-)。还有一个疑问,是否有任何选项可以将日期与标题或任务一起获取?? 当然,您可以从子查询中获取更多值,例如 Subquery(Task.objects.filter(person=OuterRef('pk')).order_by('-created_at').values('title' , 'created_at')[:1])【参考方案2】:

如果任务和历史与人相关,则需要模型之间的关系。 像这样的。

class PersonTask(models.Model):
    person = models.ForeignKey(Person, related_name="tasks", on_delete=models.CASCADE)
    title = models.TextField()
    created_at = models.DateTimeField()

class PersonHistory(models.Model):
    person = models.ForeignKey(Person, related_name="histories", on_delete=models.CASCADE)
    note = models.TextField()
    created_at = models.DateTimeField()

然后你可以得到最后一个任务和最后一个历史:

person = Person.objects.get(name="name")

person.tasks.last()
person.histories.last()

【讨论】:

型号已更新。但是我需要最新的任务和历史作为所有主要对象的带注释的 qiueryset

以上是关于Django - 查询:使用相关模型字段注释查询集的主要内容,如果未能解决你的问题,请参考以下文章

带有注释的Django查询集,为啥将GROUP BY应用于所有字段?

Django:通过注释字段的总和订购查询集?

Django 查询集优化 - 防止选择带注释的字段

注释不同的 Django 查询集不再使用不同的查询集

按外键/相关字段分组 django 查询集

具有多个字段的模型中的查询集(Django)