2017-02-23 66 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。 –

相關問題