Django REST框架|从ManyToMany字段中按计数排序

问题描述

我正在遵循Django REST框架的课程,但是在尝试将 ordering 配置从 django_filters 设置为 ViewSet 时遇到了麻烦。

ordering = ('-members__count')

在课程的原始代码中,-members__count用作查询以返回成员总数,但是当我尝试使用相同的语法时,出现此错误

错误

Cannot resolve keyword 'count' into field. Choices are: auth_token,circle,created,date_joined,email,first_name,groups,id,invitation,invited_by,is_active,is_client,is_staff,is_superuser,is_verified,issued_by,last_login,last_name,logentry,membership,modified,password,phone_number,profile,user_permissions,username

也许我误会了这个错误,但是所有这些建议的选项都对应于我模型中的Fields。另外,在“课程”中,它表示这是一种查询表示形式,用于获取该字段的总数,因此我对此感到有些困惑。

无论如何,这是我的代码的简历,但是如果需要,您也可以在此存储库中查看我的完整详细代码https://github.com/cadasmeq/comparte_ride/tree/master/cride/circles

查看:

# Filters
from rest_framework.filters import SearchFilter,OrderingFilter
from django_filters.rest_framework import DjangoFilterBackend

class CircleViewSet(mixins.CreateModelMixin,mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.ListModelMixin,viewsets.GenericViewSet):
    """Circle view set."""

    serializer_class = CircleModelSerializer
    lookup_field = 'slug_name'

    # Filters
    filter_backends = (SearchFilter,OrderingFilter,DjangoFilterBackend)
    search_fields = ('slug_name','name')
    ordering_fields = ('rides_offered','rides_taken','name','created','member_limit')
    ordering = ('-members__count','-rides_offered','-rides_taken')
    filter_fields = ('verified','is_limited')

型号:

class Circle(CRideModel):
"""Circle model.

A circle is a private group where rides are offered and taken
by its members. To join a circle a user must receive an unique
invitation code from an existing circle member.
"""

members = models.ManyToManyField(
    "users.User",through='circles.Membership',through_fields=('circle','user')
)

事先感谢很多人,对生锈的英语哈哈,我感到抱歉

解决方法

出现此错误是因为您试图访问User模型的属性。在count模型上找不到User。 我了解您要执行的操作是按照ManyToManyField members上每个圆圈的成员数进行排序。

为此,我将使用annotate,将members__count重命名为members_count并执行类似(未测试)的操作:

from django.db.models import Count

class CircleViewSet(mixins.CreateModelMixin,mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.ListModelMixin,viewsets.GenericViewSet):
    """Circle view set."""

    serializer_class = CircleModelSerializer
    lookup_field = 'slug_name'

    # Filters
    filter_backends = (SearchFilter,OrderingFilter,DjangoFilterBackend)
    search_fields = ('slug_name','name')
    ordering_fields = ('rides_offered','rides_taken','name','created','member_limit')
    ordering = ('-members_count','-rides_offered','-rides_taken')
    filter_fields = ('verified','is_limited')

    def get_queryset(self):
        """Restrict list to public-only."""
        queryset = Circle.objects.annotate(members_count=Count('members')).all()
        if self.action == 'list':
            return queryset.filter(is_public=True)
        return queryset