2017-02-23 25 views
0

我有一些产品,其中用户可以将一些标记为他最喜欢的产品。Django Rest Framework:按用户依赖的字段排序

收藏夹被建模为用户配置文件和产品之间的多对多关系。

我现在想通过API调用获取产品,但是首先按照我的喜好来订购,其他的都是次要的。现在,这取决于当前的请求,我不能通过Product.objects.all().order_by(...)来做到这一点,因为模型不知道当前用户,并且我知道现在通过序列化程序或ModelViewSet来告诉查询的方式。

我试图获得两个查询集,一个让所有的产品,一个从用户配置文件中ModelViewSet所有收藏夹,这样的:

class ProductViewSet(viewsets.ModelViewSet): 
    serializer_class = ProductCreateSerializer 
    # ... 

    def get_queryset(self): 
     favorited_products = self.request.user.profile.favorites.all() 
     products = Product.objects.all() 

     queryset = favorited_products | products 

     return queryset 

这并不工作,为实体留在这个顺序。但是这个视图返回了几百个实体,所以当我试图用return queryset[:30]来限制查询集时,默认排序似乎就会接管。

我试图做什么,甚至很容易实现?有人已经解决了类似的问题吗?

这里是我的模型:

class Product(models.Model): 
    product_name = models.CharField(max_length=200) 
    # ... 


    def __unicode__(self): 
     return self.product_name 


class Profile(models.Model): 
    user = models.OneToOneField(User, on_delete=models.CASCADE) 
    favorites = models.ManyToManyField(Product) 

    @receiver(post_save, sender=User) 
    def create_user_profile(sender, instance, created, **kwargs): 
     if created: 
      Profile.objects.get_or_create(user=instance) 

    @receiver(post_save, sender=User) 
    def save_user_profile(sender, instance, **kwargs): 
     instance.profile.save() 

我的串行:

class FavoriteField(serializers.BooleanField): 
    def get_attribute(self, instance): 

     return self.context['request'].user.profile.favorites.filter(pk=instance.pk).exists() 

class ProductSerializer(serializers.ModelSerializer): 
    favorite = FavoriteField() 

    def update(self, instance, validated_data): 
     instance = super().update(instance, validated_data) 
     is_favourite = validated_data.get('favorite') # can be None 
     if is_favourite is True: 
      self.context['request'].user.profile.favorites.add(instance) 
     elif is_favourite is False: 
      self.context['request'].user.profile.favorites.remove(instance) 
     return instance 

回答

2

我已经找到了解决方案,使用计数,案例和IntegerField:

user_id = self.request.user.pk 
queryset = Product.objects \ 
     .annotate(favorited=Count(Case(When(favorited_by__user__pk=user_id, then=1), output_field=IntegerField()))) \ 
     .order_by("-favorited") 
+0

伟大的解决方法!我想指出kwarg应该是'output_field' – wasabigeek

+0

谢谢@wasabigeek。我也修好了kwarg。 –

相关问题