[python] 다른 범주에서 가장 최근의 개체를 가져 오는 Django 쿼리

두 가지 모델 AB. 모든 B개체에는 개체에 대한 외래 키가 A있습니다. A개체 집합이 주어지면 ORM을 사용하여 BA개체 에 대해 생성 된 가장 최근 개체를 포함하는 개체 집합을 가져올 수 있습니까 ?

다음은 간단한 예입니다.

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_cak‌​e_id', flat=True)

hottest_cakes = Cake.objects.filter(id__in=hottest_cake_ids)

이에 대한 BTW 크레딧은 한때 저의 비슷한 질문에 답한 Daniel Roseman에게 돌아갑니다.

http://groups.google.pl/group/django-users/browse_thread/thread/3b3cd4cbad478d34/3e4c87f336696054?hl=pl&q=

위의 방법이 너무 느리면 두 번째 방법도 알고 있습니다. 관련 베이커리에서 가장 인기있는 Cakes 만 생성하는 사용자 지정 SQL을 작성하고 데이터베이스 VIEW로 정의한 다음 관리되지 않는 Django 모델을 작성할 수 있습니다. 위의 django-users 스레드에서도 언급되었습니다. 원래 개념에 대한 직접 링크는 다음과 같습니다.

http://web.archive.org/web/20130203180037/http://wolfram.kriesing.de/blog/index.php/2007/django-nice-and-critical-article#comment-48425

도움이 되었기를 바랍니다.


답변

에서 시작 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_bydistinct그래서 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와 같은 다른 것들을 구현할 수도 있습니다.