Django - filtragem em objetos relacionados

votos
14

Para a minha aplicação Django Eu tenho Eventos, classificações e Usuários. As avaliações são relacionadas a eventos e usuários através de uma chave estrangeira. Ao exibir uma lista de eventos que eu quero para filtrar as classificações do evento por um user_id então eu sei se um evento foi avaliado pelo usuário.

Se eu fizer:

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

(Request.user.id dá o user_id do atual usuário conectado) ... então eu só obter os eventos que são classificados pelo usuário e não toda a lista de eventos.

O que eu preciso pode ser gerado através do SQL personalizado:

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

Existe uma maneira mais fácil para que eu não tenho que usar SQL personalizado?

Publicado 02/11/2008 em 01:43
fonte usuário
Em outras línguas...                            


4 respostas

votos
15

O filtermétodo é para filtragem quais objetos são devolvidos com base nos critérios especificados, por isso não é o que você quer aqui. Uma opção é fazer uma segunda consulta para recuperar todas as notas de dados Eventobjetos para o atual User.

modelos:

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

Visão:

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

Modelo:

{% for event, user_rating in events %}
  {% if user_rating %} ... {% endif %}
{% endfor %}
Respondeu 02/11/2008 em 12:21
fonte usuário

votos
4

Além sugestão de S. Lott, você pode considerar o uso de select_related () para limitar o número de consultas de banco de dados; caso contrário, o modelo vai fazer uma consulta na passagem de cada evento através do laço.

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

O parâmetro de profundidade não é necessária, mas se os seus outros modelos têm chaves estrangeiras adicionais que irá limitar o número de junta.

Respondeu 02/11/2008 em 03:08
fonte usuário

votos
1

Para fazer melhor uso do Django, você tem que evitar tentando fazer junta.

A "junção externa esquerda" é na verdade uma lista de objetos com relacionamentos opcionais.

É simplesmente uma lista de eventos, Event.objects.all(). Alguns objetos Event tem uma classificação, outros não.

Você obter a lista de Eventos, na sua vista. Você lida com as relações opcionais em seu modelo.

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

é um ponto de partida.

Respondeu 02/11/2008 em 01:52
fonte usuário

votos
0

Eu acho que você tem que fazer algo assim.

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})
Respondeu 27/07/2010 em 07:25
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more