Django-在yelp之类的应用中过滤掉已经评级的餐厅 [英] Django - filtering out already rated restaurants in yelp like app

查看:61
本文介绍了Django-在yelp之类的应用中过滤掉已经评级的餐厅的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下数据库模型:

Consider the following database model:

class User:
    id         = models.BigAutoField(primary_key=True)
    first_name = models.CharField(max_length=50)
    last_name  = models.CharField(max_length=50)

class Restaurant:
    id    = models.BigAutoField(primary_key=True)
    title = models.CharField(max_length=50)

class Rating:
    id             = models.BigAutoField(primary_key=True)
    by_user        = models.ForeignKey(to='User',
                                       on_delete=models.PROTECT,
                                       related_name='written_ratings')
    for_restaurant = models.ForeignKey(to='Restaurant',
                                       on_delete=models.PROTECT,
                                       related_name='received_ratings')
    score          = models.SmallIntegerField() 

    # make sure only one vote per user per restaurant
    class Meta:
        unique_together = ('by_user', 'for_restaurant')

对于给定的用户,通过执行以下查询,我们可以获得尚未评级的餐馆的列表(我从我的最新帖子中学到的东西)

For a given User, we can obtain a list of Restaurant that we have not yet rated by performing the following query (that I have learned from my last post)

eligible_restaurants = Restaurant.objects.exclude(rating__by_user_id=my_id)

但是,当评分不直接指向餐馆-而是位于中间的个人资料对象上?

But what happens when the Ratings don't point directly at the Restaurants - but rather at an intermediate Profile object?

class User:
    id         = models.BigAutoField(primary_key=True)
    first_name = models.CharField(max_length=50)
    last_name  = models.CharField(max_length=50)

class Restaurant:
    id              = models.BigAutoField(primary_key=True)
    title           = models.CharField(max_length=50)
    current_profile = models.OneToOneField(to='Profile',
                                           on_delete=models.PROTECT,
                                           related_name='+')
    # the `+` means to not generate a related name

class Profile:
    # this is here acting as an intermediate between
    # `Restaurant` and `Rating` so that we can keep track
    # of all reviews - deleting/remaking would simply be
    # creating a new `Profile` and setting the `Restaurant`
    # to point to it instead - the old one will act as a
    # historical record
    id            = models.BigAutoField(primary_key=True)
    by_restaurant = models.ForeignKey(to='Restaurant',
                                      on_delete=models.PROTECT,
                                      related_name='written_profiles')
    picture_url   = models.CharField(max_length=500)
    picture_desc  = models.CharField(max_length=500)

class Rating:
    id             = models.BigAutoField(primary_key=True)
    by_user        = models.ForeignKey(to='User',
                                       on_delete=models.PROTECT,
                                       related_name='written_ratings')
    for_profile    = models.ForeignKey(to='Profile',
                                       on_delete=models.PROTECT,
                                       related_name='received_ratings')
    score          = models.SmallIntegerField()

    # make sure only one vote per user per restaurant
    class Meta:
        unique_together = ('by_user', 'for_profile')

如何查询

推荐答案

您可以从餐馆开始过滤它们

You could filter them starting with restaurants

restaurant_ids = Rating.objects.filter(by_user=user).values_list('for_profile__by_restaurant', flat=True).distinct()
eligible_restaurants = Restaurant.objects.exclude(id__in=restaurant_ids)

注意:由于django的查询集是惰性的,因此只会生成一个查询。

Note: this will generate only one query because django's querysets are lazy.

这篇关于Django-在yelp之类的应用中过滤掉已经评级的餐厅的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆