web-dev-qa-db-ja.com

Django-関連オブジェクトのフィルタリング

私のDjangoアプリには、イベント、評価、ユーザーがあります。評価は、外部キーを介してイベントとユーザーに関連付けられています。イベントのリストを表示するときに、イベントの評価をフィルター処理したいuser_idなので、イベントがユーザーによって評価されているかどうかがわかります。

私が行った場合:

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を使用する必要がないようにする簡単な方法はありますか?

18
Tim Graham

filterメソッドは、指定された基準に基づいて返されるオブジェクトをフィルタリングするためのものであるため、ここで必要なものではありません。 1つのオプションは、2番目のクエリを実行して、現在の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 %}
16
Jonny Buchanan

S.Lottの提案に加えて、select_related()を使用してデータベースクエリの数を制限することを検討してください。それ以外の場合、テンプレートは各イベントのループ通過時にクエリを実行します。

Event.objects.all().select_related(depth=1)

深さパラメーターは必須ではありませんが、他のモデルに追加の外部キーがある場合は、結合の数が制限されます。

4
Daniel Naab

Djangoを最大限に活用するには、結合を試みないようにする必要があります。

「左外部結合」は、実際にはオプションの関係を持つオブジェクトのリストです。

これは単にイベントのリスト、Event.objects.all()です。一部のイベントオブジェクトには評価があり、一部にはありません。

ビューにイベントのリストが表示されます。テンプレートでオプションの関係を処理します。

{% for e in event_list %}
    {{ e }}
    {% if e.rating_set.all %}{{ e.rating_set }}{% endif %}
{% endfor %}

出発点です。

1
S.Lott

私はあなたがこのようなことをしなければならないと思います。

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})
0