Django REST框架:按用户依赖性字段订购



我有一些产品,其中用户可以将其中一些标记为他喜欢的产品。

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

我现在想通过API呼叫获取产品,但首先按收藏夹订购,其次是其他所有内容。现在,由于这取决于当前请求,因此我无法通过Product.objects.all().order_by(...)进行此操作,因为该模型不知道当前用户,并且我现在知道通过序列化器或ModelViewSet告诉查询的方法。

我尝试获取两个QuerySet,一个带有所有产品,一个来自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]限制QuerySet时,默认订购似乎会接管。

我想做的是容易实现的目标吗?有人已经解决了类似的问题吗?

这是我的模型:

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

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

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

最新更新