How to order django rest framework queryset from s

2019-07-15 03:35发布

How can I order a Django QuerySet from a serializer field? Since the field is too complicated, I couldn't order the QuerySet using annotate and I cannot store the value in the model as well.

Edit:

Serializer

class DrinkListModelSerializer(serializers.ModelSerializer):
    count_need = serializers.SerializerMethodField()
    url = drink_detail_url

    class Meta:
        model = Drink
        fields = [
            'name',
            'count_need',
            'thumbnail',
            'url'
        ]

    def get_count_need(self, obj):
        drink_ingredient_qs = obj.ingredients.all()
        user = self.context['request'].user
        user_qs = User.objects.filter(username=user.username)
        if user_qs.exists() and user_qs.count() == 1:
            user_obj = user_qs.first()
            user_ingredient_qs = user_obj.ingredient_set.all()
            return (user_ingredient_qs & drink_ingredient_qs).count()
        return 0

Models:

class Drink(models.Model):
    name                = models.CharField(max_length = 1000, null=True, blank=True)
    ingredients         = models.ManyToManyField(Ingredient, blank=True)
    user                = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True)

class Ingredient(models.Model):
    name                = models.CharField(max_length = 1000)
    ingredient_category = models.ForeignKey(Category, null=True, blank=True)
    slug                = models.SlugField(max_length=255, unique=True)
    user                = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True)

View

class DrinkListAPIView(ListAPIView):
serializer_class = DrinkListModelSerializer
pagination_class = LargeResultsSetPagination
permission_classes = [AllowAny]

def get_queryset(self, *args, **kwargs):
    user = self.request.user
    qs = Drink.objects.all()
    userQuery = self.request.GET.get('user')
    query = self.request.GET.get("q")
    filters = self.request.GET.getlist('filter')
    if query:
        qs = qs.filter(name__icontains=query)
    elif filters:
        qs = qs.filter(playlist__name__iexact=filters[0])
        for filter in filters[1:]:
            qs = qs | Drink.objects.filter(playlist__name__iexact=filter)
    elif userQuery and user.is_authenticated():
        qs = qs.filter(user=user)
    return qs.order_by('-timestamp')

Currently, I'm ordering the queryset by timestamp since it is in the model it self, but i need to order it by 'count_need' which is part of the serializer. I tried to do something like qs = qs.annotate(count_need=Count('ingredients' & user_ingredient_qs)).order_by(count_need) but this clearly doesnt work since 'ingredients' is just a string here and not the Drink's ingredient queryset.

1条回答
迷人小祖宗
2楼-- · 2019-07-15 03:47

One way that might work well is to implement and customize to_representation on the list serializer:

def to_representation(self, data):
    iterable = data.all() if isinstance(data, models.Manager) else data

    iterable = sorted(iterable, key=lambda x: x.count_need)

    return [
        self.child.to_representation(item) for item in iterable
    ]
查看更多
登录 后发表回答