문제
Django 앱의 경우 이벤트, 등급 및 사용자가 있습니다. 등급은 외국 키를 통해 이벤트 및 사용자와 관련이 있습니다. 이벤트 목록을 표시 할 때 사용자가 이벤트의 등급을 필터링하려면 사용자가 이벤트를 평가했는지 알 수 있습니다.
만약 내가한다면:
event_list = Event.objects.filter(rating__user=request.user.id)
(request.user.id는 현재 로그인 한 사용자의 user_id를 제공합니다) ... 그런 다음 전체 이벤트 목록이 아닌 사용자가 평가 한 이벤트 만 얻습니다.
사용자 정의 SQL을 통해 필요한 것은 다음과 같습니다.
SELECT *
FROM `events_event`
LEFT OUTER JOIN (
SELECT *
FROM `events_rating`
WHERE user_id = ##
) AS temp
ON events_event.id = temp.user_id
더 쉬운 방법이 있으므로 사용자 정의 SQL을 사용할 필요가 없습니까?
해결책
그만큼 filter
방법은 지정된 기준에 따라 반환되는 객체를 필터링하는 것이므로 여기에서 원하는 것이 아닙니다. 한 가지 옵션은 주어진 모든 등급을 검색하기 위해 두 번째 쿼리를 수행하는 것입니다. Event
전류에 대한 객체 User
.
모델 :
import collections
from django.db import models
class RatingManager(models.Manager):
def get_for_user(self, events, user):
ratings = self.filter(event__in=[event.id for event in events],
user=user)
rating_dict = collections.defaultdict(lambda: None)
for rating in ratings:
rating_dict[rating.event_id] = rating
return rating_dict
class Rating(models.Model):
# ...
objects = RatingManager()
보다:
events = Event.objects.all()
user_ratings = Rating.objects.get_for_user(events, request.user)
context = {
'events': [(event, user_ratings[event.id]) for event in events],
}
주형:
{% for event, user_rating in events %}
{% if user_rating %} ... {% endif %}
{% endfor %}
다른 팁
S.Lott의 제안 외에도 select_related ()를 사용하여 데이터베이스 쿼리 수를 제한하는 것을 고려할 수 있습니다. 그렇지 않으면 템플릿이 각 이벤트의 루프를 통과하는 쿼리를 수행합니다.
Event.objects.all().select_related(depth=1)
깊이 매개 변수는 필요하지 않지만 다른 모델에 추가적인 외부 키가있는 경우 조인 수가 제한됩니다.
Django를 최대한 활용하려면 가입을 피해야합니다.
"왼쪽 외부 조인"은 실제로 선택적 관계가있는 객체 목록입니다.
단순히 이벤트 목록입니다. Event.objects.all()
. 일부 이벤트 객체에는 등급이 있으며 일부는 그렇지 않습니다.
당신은 당신의 관점에서 이벤트 목록을 얻습니다. 템플릿의 선택적 관계를 처리합니다.
{% for e in event_list %}
{{ e }}
{% if e.rating_set.all %}{{ e.rating_set }}{% endif %}
{% endfor %}
점프 포인트입니다.
나는 당신이 이런 일을해야한다고 생각합니다.
events=Event.objects.filter(rating__user=request.user.id)
ratings='(select rating from ratings where user_id=%d and event_id=event_events.id '%request.user.id
events=events.extra(select={'rating':ratings})