big*_*ose 5 django annotations join django-models
如何在单个表达式中从多对一关系的过滤结果中获取最新值以注释 Django QuerySet?
鉴于此玩具模式:
from django.db import models
class Lorem(models.Model):
""" Lorem ipsum, dolor sit amet. """
class LoremStatusEvent(models.Model):
""" A status event change on a given `ipsum` for a `lorem`. """
created = models.DateTimeField(auto_now_add=True)
lorem = models.ForeignKey(Lorem)
ipsum = models.CharField(max_length=200)
status = models.CharField(max_length=10)
Run Code Online (Sandbox Code Playgroud)
为了在Django LoremAdmin
(用于Lorem
模型)中创建自定义QuerySet ,我需要:
foo_status
和bar_status
每个从分开的JOIN子句到一个LoremStatusEvent
模型:lorem.loremstatusevent_set__status
。Ipsum
值的事件:foo_status_events=LoremStatusEvent.filter(ipsum='foo')
。foo_status=LoremStatusEvent.objects.filter(ipsum='foo').latest('created').status
。foo_status
和。bar_status
queryset = queryset.annotate(foo_status=???).annotate(bar_status=???)
如果我发明了一些功能来做到这一切- ,get_field
,,latest_by
-我可以写管理员是这样的:filter_by
loremstatus_set_of_every_corresponding_lorem
from django.contrib import admin
class LoremAdmin(admin.ModelAdmin):
""" Django admin for `Lorem` model. """
class Meta:
model = Lorem
def get_queryset(request):
""" Get the `QuerySet` of all instances available to this admin. """
queryset = super().get_queryset(request)
queryset.annotate(
foo_status=(
get_field('status')(
latest_by('created')(
filter_by(ipsum='foo')(
loremstatusevent_set_of_every_corresponding_lorem)))),
bar_status=(
get_field('status')(
latest_by('created')(
filter_by(ipsum='bar')(
loremstatusevent_set_of_every_corresponding_lorem)))),
)
return queryset
Run Code Online (Sandbox Code Playgroud)
哪些实际功能应替换这些占位符名称中的每个?
loremstatus_set_of_every_corresponding_lorem
,相当于Lorem.loremstatusevent_set
。filter_by
,以过滤右侧的联接。latest_by
,以汇总结果集(按字段排序)以获取单个最新实例。我没有看到任何这样记录的聚合函数。get_field
,以引用结果实例中的字段。请记住,所有这些操作都需要在Lorem
实例的查询集上完成,并通过Lorem.loremstatusevent_set
;来访问相关实例。LoremStatusEvent
那时我没有实例,所以我不能直接使用的属性LoremStatusEvent
。
那么,上述占位符应包含什么实际的Django功能?
您应该能够使用新的Subquery功能来做到这一点,该功能也可以作为向1.8+的反向移植。
try:
from django.db.models.expressions import Subquery, OuterRef
except ImportError:
from django_subquery.expressions import Subquery, OuterRef
class LoremAdmin(admin.ModelAdmin):
# …
def get_queryset(request):
queryset = super().get_queryset(request)
status_event_per_lorem = LoremStatusEvent.objects.filter(
lorem=OuterRef('pk'))
latest_status_event_per_lorem = (
status_event_per_lorem.order_by(
'pk', '-created').distinct('pk'))
latest_status_event_for_ipsum_foo = (
latest_status_event_per_lorem.filter(ipsum='foo'))
latest_status_event_for_ipsum_bar = (
latest_status_event_per_lorem.filter(ipsum='bar'))
queryset = queryset.annotate(
foo_status=Subquery(
latest_status_event_for_ipsum_foo.values('status')[:1]),
bar_status=Subquery(
latest_status_event_for_ipsum_bar.values('status')[:1]),
)
return queryset
Run Code Online (Sandbox Code Playgroud)