2017-11-22 1 views
1

외래 키 테이블을 기반으로 기본 '즐겨 찾기'시스템을 구현하려고합니다.부울 주석으로 인해 중복이 발생합니까?

의 나는 다음과 같은 간단한 모델을 가지고 있다고 가정 해 봅시다 :

이제
class Item(models.Model) 
    id = models.IntegerField() 

class User(models.Model) 
    id = models.IntegerField() 

class UserFavourites(models.Model) 
    user = models.ForeignKey(User, related_name='user_for_fav_rel') 
    item = models.ForeignKey(Item, related_name='item_for_fav_rel') 

나는 그들이 사용자가 즐겨 찾기로 표시 한 경우 항목에 대한 다음의 검색어보고 생성 :

queryset = Item.objects.all() 

USER_ID = request.user.id 

queryset = queryset.annotate(
    favourite=Case(
     When(
      item_for_fav_rel__user__id=USER_ID, 
      then=Value('True') 
     ), 
     default=Value('False'), 
     output_field=BooleanField() 
    ) 
) 

모든 이 작품의 위대한 작품이지만, 응답에 항목이 실제로 favourited 경우, 나는 그 특정 항목의 복사본을 queryset에 나타납니다. 어떤 생각을 어떻게 피할 수 있습니까?

(내가 생각하는 최소한의 예를 아래로 편집 ...)

결과 SQL 쿼리

SELECT 
    "core_item"."id", 
    CASE 
     WHEN "core_userfavourites"."user_id" = 1 THEN True 
     ELSE False 
    END AS "favourite" 
FROM "core_item" 
LEFT OUTER JOIN "core_userfavourites" 
    ON ("core_item"."id" = "core_userfavourites"."item_id") 
+0

생성되는 SQL 쿼리는 무엇입니까? –

+0

질문 편집을 참조하십시오 ... – Eric

+0

'all()'을 사용하고'annotate()'를 사용하는 특별한 이유가 있습니까? – scharette

답변

1

문제는 당신이 core_item 및 core_userfavorites의 각 조합에 대해 하나 개의 행을 얻고있다. 거기 원시 SQL없이 노력하고 정확히 할 수있는 방법이 될 것 같다,하지만 다행히 장고는 아주 최근 (1.11) 여기

from django.db.models.expressions import OuterRef, Subquery 

queryset = Item.objects.all() 

USER_ID = request.user.id 
user_favorites = UserFavourites.objects.filter(
    user_id=USER_ID, 
    item_id=OuterRef('id') 
)[:1].values('user_id') 

queryset = queryset.annotate(user_favorite=Subquery(user_favorites)) 

이 의지를 사용하여 하위 쿼리 절을 작성하는 기능을 추가하지 않습니다 사용자가 선호하는 경우 user_favorite 필드에 user_id을 입력하고 그렇지 않은 경우 None을 입력하십시오.

기본적으로 관련 테이블에서 임의의 값을 선택하는 하위 쿼리를 작성하고 있습니다.

+0

감사합니다. Vinay! 나는 오늘 밤 나중에 이것을 시험해 볼 것이다. 질문 : 하위 쿼리를 왜 자르고 있습니까? 부울 결과에 적용 할 수 있습니까? – Eric

+0

하위 쿼리가 두 개 이상의 행을 반환하면 쿼리가 실패합니다. 이 경우에는 필요하지 않을 수도 있습니다. 원래 표현식에있는 경우와 마찬가지로 하위 쿼리를 래핑하여 부울 결과로 바꿀 수 있습니다. None은 False로 평가되고 user_id의 다른 값은 True로 평가됩니다. 나는 그것이 약간 추한 것을 인정할 것이다. exists()가 실행을 트리거하고 즉시 값을 반환하는 대신 쿼리 세트 또는 다른 체인 가능한 객체를 반환 할 수 있으면 좋을 것입니다. –

+1

다시 한번 감사드립니다! 이것은 잘 작동합니다. 장고 Rest 프레임 워크의 일환으로 '항목'의 시리얼 라이저에서 True/False로 감쌀 수있었습니다. – Eric

관련 문제