Frage

Für meine Django app habe ich Veranstaltungen, Bewertungen und Benutzer. Bewertungen beziehen sich auf Ereignisse und Benutzer über einen Fremdschlüssel. Wenn Sie eine Liste der Ereignisse Anzeigen Ich möchte von einem User_id die Ratings der Veranstaltung filtern, damit ich weiß, ob ein Ereignis vom Benutzer gelesen wurde.

Wenn ich das tue:

event_list = Event.objects.filter(rating__user=request.user.id)

(request.user.id gibt die user_id der aktuellen angemeldeten Benutzer) ... dann habe ich nur die Ereignisse erhalten, die durch den Benutzer und nicht die gesamte Liste der Ereignisse bewertet werden.

Was ich brauche, kann durch die benutzerdefinierte SQL erzeugt werden:

SELECT *
FROM `events_event`
LEFT OUTER JOIN (
  SELECT *
  FROM `events_rating`
  WHERE user_id = ##
  ) AS temp 
ON events_event.id = temp.user_id

Gibt es einen einfacheren Weg, so habe ich nicht benutzerdefinierte SQL verwenden?

War es hilfreich?

Lösung

Die filter Methode ist für die Filterung, welche Objekte auf der Grundlage der angegebenen Kriterien zurückgegeben werden, so ist es nicht das, was Sie hier wollen. Eine Möglichkeit ist, eine zweite Abfrage zu tun, alle Bewertungen für gegeben Event Objekte für die aktuelle User abgerufen werden.

Modelle:

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()

Ausblick:

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],
}

Vorlage:

{% for event, user_rating in events %}
  {% if user_rating %} ... {% endif %}
{% endfor %}

Andere Tipps

Neben S.Lott Vorschlag, können Sie mit Hilfe betrachten select_related () die Anzahl der Datenbankabfragen zu begrenzen; sonst wird Ihre Vorlage wird auf jeden Fall der Durchlauf durch die Schleife eine Abfrage tun.

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

Die Tiefe Parameter ist nicht erforderlich, aber wenn die anderen Modelle zusätzliche Fremdschlüssel haben sie die Zahl begrenzen, schließt sich.

Zur optimalen Nutzung von Django machen, müssen Sie vermeiden versuchen, schließt sich zu tun.

Eine „linke äußere Verknüpfung“ ist eigentlich eine Liste von Objekten mit optionalen Beziehungen.

Es ist einfach eine Liste von Veranstaltungen, Event.objects.all(). Einige Event-Objekte haben eine Bewertung, manche nicht.

Sie erhalten die Liste der Ereignisse aus Ihrer Sicht. Sie behandeln die optionalen Beziehungen in Ihrer Vorlage.

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

ist ein Startpunkt.

Ich glaube, Sie, so etwas zu tun haben.

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})
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top