Фильтр Django с аннотацией - PullRequest
0 голосов
/ 21 марта 2012
class Review(models.Model):
    slug = models.SlugField(max_length=255, unique=True)
    vendor = models.ForeignKey(Vendor)
    user = models.ForeignKey(User, blank=True, null=True)
    product = models.ForeignKey(Product, blank=True, null=True)
    images = models.ManyToManyField(ReviewImage, blank=True, null=True)
    headline = models.CharField(max_length=100)
    review = models.TextField(blank=True, null=True)
    rating = models.IntegerField()
    active = models.BooleanField(default=1)
    created = models.DateTimeField(auto_now_add=True)
    changed = models.DateTimeField(auto_now=True)

# This is the problem... I works, but no vendor is shown if there is no review.
vendor_list = (Vendor.objects.filter(category=category,
                                     review__product__isnull=True,
                                     active=True)
               .annotate(rating_avg=Avg('review__rating')))

КАК я могу сделать это с review__product__isnull=True?Если обзора нет вообще, я все равно хочу продавца, но рейтинг должен быть: "0", .. что делать?

Ответы [ 2 ]

1 голос
/ 21 марта 2012

Посмотрим, пойму ли я это. Вы пытаетесь перечислить всех активных поставщиков в категории, снабженных средней оценкой их отзывов. То, как вы определяете, что обзор является обзором поставщика, а не обзором продукта, заключается в том, что поле продукта является пустым. И вы хотите, чтобы средний рейтинг поставщиков без отзывов был равен нулю.

В SQL ваш запрос требует OUTER JOIN:

SELECT vendor.id, COALESCE(AVG(review.rating), 0.0) AS rating
  FROM myapp_vendor AS vendor
  LEFT OUTER JOIN myapp_review AS review
    ON review.vendor_id = vendor.id
       AND review.product IS NULL
  WHERE vendor.category = %s
    AND vendor.active
  GROUP BY vendor.id

Иногда в Django самым простым решением является необработанный SQL-запрос : как утверждают разработчики, API базы данных - это " ярлык, но не обязательно конечный результат""Так это будет выглядеть так:

for v in Vendor.objects.raw('SELECT ... ', [category]): # query as above
    print 'Vendor {0} has rating {1}'.format(v.name, v.rating)
0 голосов
/ 21 марта 2012

ОК, я могу ошибаться здесь.Я провел небольшой тест, и он дал мне правильный результат, но мне пришлось бы тратить больше времени на тестирование, а у меня его сейчас нет.

Вы можете попробовать это:

vendor_list = Vendor.objects.filter(category=category, active=True)
vendor_list = vendor_list.filter(Q(review__product__isnull=True)|Q(review__isnull=True)).annotate(rating_avg=Avg('review__rating'))

(Фильтр разделен на две строки, чтобы его было легче читать, но его можно объединить)

Идея состоит в том, что сначала вы выбираете всех поставщиков, а затем фильтруете тех, у кого либо нет отзывов о товаре, либо нет отзывов навсе.Затем вы аннотируете их.

Рейтинг тех поставщиков, у которых отсутствует отзыв, будет Нет, не 0.

...