2017-02-23 39 views
0

У меня есть некоторые продукты, из которых пользователь может отметить некоторые из своих любимых продуктов.Django Rest Framework: порядок от пользователя зависит от поля

Избранные моделируются как отношение многих к многим между профилем пользователя и продуктом.

Теперь я хотел бы получить продукты через API-вызов, но сначала заказывал по избранным, а все остальное второй. Теперь, поскольку это зависит от текущего запроса, я не могу сделать это через Product.objects.all().order_by(...), так как модель не знает текущего пользователя, и теперь я знаю, как рассказать запрос через сериализатор или ModelViewSet.

Я пытался получить два querysets, один со всеми продуктами, один со всеми фаворитами из профиля пользователя в 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

Я нашел решение, используя граф, Case и 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. –

Смежные вопросы