두 가지 모델 A
과 B
. 모든 B
개체에는 개체에 대한 외래 키가 A
있습니다. A
개체 집합이 주어지면 ORM을 사용하여 B
각 A
개체 에 대해 생성 된 가장 최근 개체를 포함하는 개체 집합을 가져올 수 있습니까 ?
다음은 간단한 예입니다.
class Bakery(models.Model):
town = models.CharField(max_length=255)
class Cake(models.Model):
bakery = models.ForeignKey(Bakery, on_delete=models.CASCADE)
baked_at = models.DateTimeField()
그래서 저는 미국 Anytown의 각 빵집에서 구운 최신 케이크를 반환하는 쿼리를 찾고 있습니다.
답변
내가 아는 한, Django ORM에서이 작업을 수행하는 한 단계의 방법은 없습니다.
그러나 두 가지 쿼리로 분할 할 수 있습니다.
bakeries = Bakery.objects.annotate(
hottest_cake_baked_at=Max('cake__baked_at')
)
hottest_cakes = Cake.objects.filter(
baked_at__in=[b.hottest_cake_baked_at for b in bakeries]
)
케이크의 id가 bake_at 타임 스탬프와 함께 진행되는 경우 위 코드를 단순화하고 명확하게 할 수 있습니다 (두 개의 케이크가 동시에 도착하는 경우 둘 다 얻을 수 있습니다).
hottest_cake_ids = Bakery.objects.annotate(
hottest_cake_id=Max('cake__id')
).values_list('hottest_cake_id', flat=True)
hottest_cakes = Cake.objects.filter(id__in=hottest_cake_ids)
이에 대한 BTW 크레딧은 한때 저의 비슷한 질문에 답한 Daniel Roseman에게 돌아갑니다.
위의 방법이 너무 느리면 두 번째 방법도 알고 있습니다. 관련 베이커리에서 가장 인기있는 Cakes 만 생성하는 사용자 지정 SQL을 작성하고 데이터베이스 VIEW로 정의한 다음 관리되지 않는 Django 모델을 작성할 수 있습니다. 위의 django-users 스레드에서도 언급되었습니다. 원래 개념에 대한 직접 링크는 다음과 같습니다.
도움이 되었기를 바랍니다.
답변
에서 시작 Django 1.11
및 덕분에 하위 쿼리 및 OuterRef 우리는 마침내 구축 할 수 latest-per-group
를 사용하여 쿼리를 ORM
.
hottest_cakes = Cake.objects.filter(
baked_at=Subquery(
(Cake.objects
.filter(bakery=OuterRef('bakery'))
.values('bakery')
.annotate(last_bake=Max('baked_at'))
.values('last_bake')[:1]
)
)
)
#BONUS, we can now use this for prefetch_related()
bakeries = Bakery.objects.all().prefetch_related(
Prefetch('cake_set',
queryset=hottest_cakes,
to_attr='hottest_cakes'
)
)
#usage
for bakery in bakeries:
print 'Bakery %s has %s hottest_cakes' % (bakery, len(bakery.hottest_cakes))
답변
PostGreSQL을 사용하는 경우 Django의 인터페이스를 사용 하여 DISTINCT ON 할 수 있습니다 .
recent_cakes = Cake.objects.order_by('bakery__id', '-baked_at').distinct('bakery__id')
으로 워드 프로세서는 , 당신이해야 말 order by
같은 필드 당신 그 distinct on
. Simon이 아래에서 지적했듯이 추가 정렬을 수행하려면 Python 공간에서 수행해야합니다.
답변
이 작업을 수행해야합니다.
from django.db.models import Max
Bakery.objects.annotate(Max('cake__baked_at'))
답변
나는 비슷한 문제로 싸우고 마침내 해결책을 찾았습니다. 그것은에 의존하지 않는 order_by
및 distinct
그래서 DB 측에 요구하고 또한 필터링 중첩 된 쿼리로 사용할 수 있습니다로 정렬 할 수 있습니다. 또한이 구현은 표준 SQL HAVING
절을 기반으로하기 때문에 db 엔진에 독립적이라고 생각합니다 . 유일한 단점은 베이커리에서 정확히 동시에 구운 경우 베이커리 당 여러 개의 가장 뜨거운 케이크를 반환한다는 것입니다.
from django.db.models import Max, F
Cake.objects.annotate(
# annotate with MAX "baked_at" over all cakes in bakery
latest_baketime_in_bakery=Max('bakery__cake_set__baked_at')
# compare this cake "baked_at" with annotated latest in bakery
).filter(latest_baketime_in_bakery__eq=F('baked_at'))
답변
Cake.objects.filter(bakery__town="Anytown").order_by("-created_at")[:1]
나는 내 목적으로 모델을 구축하지 않았지만 이론적으로 이것은 작동합니다. 세분화 :
Cake.objects.filter(bakery__town="Anytown")
국가가 문자열의 일부가 아니라고 가정하고 “Anytown”에 속한 모든 케이크를 반환해야합니다.bakery
와 사이의 이중 밑줄town
을 사용하면의town
속성에 액세스 할 수 있습니다bakery
..order_by("-created_at")
생성 된 날짜, 가장 최근의 순서로 결과를 정렬합니다-
((마이너스) 기호에 유의하십시오"-created_at"
. 빼기 기호가 없으면 가장 오래된 것부터 가장 최근의 것 순 으로 정렬됩니다.[:1]
마지막에는 반환되는 목록의 첫 번째 항목 만 반환합니다 (Anytown의 케이크 목록이 가장 최근의 순서로 정렬 됨).
참고 :이 답변은 Django 1.11 용입니다.
이 답변 은 Django 1.11 문서에 표시된 쿼리에서 수정되었습니다 .
답변
위의 @Tomasz Zieliński 솔루션이 문제를 해결했지만 여전히 Cake를 필터링해야하므로 내 문제를 해결하지 못했습니다. 그래서 여기 내 해결책이 있습니다.
from django.db.models import Q, Max
hottest_yellow_round_cake = Max('cake__baked_at', filter=Q(cake__color='yellow', cake__shape='round'))
bakeries = Bakery.objects.filter(town='Chicago').annotate(
hottest_cake_baked_at=hottest_yellow_round_cake
)
hottest_cakes = Cake.objects.filter(
baked_at__in=[b.hottest_cake_baked_at for b in bakeries]
)
이 접근 방식을 사용하면 Filter, Ordering, Pagination for Cakes와 같은 다른 것들을 구현할 수도 있습니다.