Django - 像app一样过滤掉已经评价过的餐馆

时间:2017-07-16 23:46:12

标签: python django django-models

考虑以下数据库模型:

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

对于给定的User,我们可以通过执行以下查询(我从my last post了解到的)获得我们尚未评级的Restaurant列表

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

但是当Ratings没有直接指向Restaurants而是指向中间Profile对象时会发生什么?

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

我现在如何查询符合条件的餐馆?

1 个答案:

答案 0 :(得分:1)

您可以从餐馆

开始过滤它们
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的查询集很懒。