使用多个查找字段休息调用以进行反向查找

时间:2014-01-26 16:15:52

标签: python django rest django-rest-framework

在Django休息框架中,有没有办法拥有多个查找字段?我知道它听起来不是那么 REST 友好。

我有一个Company模型,我想首先在他们的国家/地区列出它们,然后是一个slug字段,例如:/companies/<iso_country>/<slug>/。有没有办法做到这一点?

3 个答案:

答案 0 :(得分:10)

创建mixin,如:

class MultipleFieldLookupMixin(object):
    def get_object(self):
        queryset = self.get_queryset()             # Get the base queryset
        queryset = self.filter_queryset(queryset)  # Apply any filter backends
        filter = {}
        for field in self.lookup_fields:
            filter[field] = self.kwargs[field]
        return get_object_or_404(queryset, **filter)  # Lookup the object

并将此mixin添加到您的视图集中:

class YourCountryViewSet(MultipleFieldLookupMixin, generics.RetrieveAPIView):
    lookup_fields = ('iso_country', 'slug')

...

来源:http://www.django-rest-framework.org/api-guide/generic-views/#creating-custom-mixins

答案 1 :(得分:0)

假设您正在使用路由器,我认为您可以执行以下操作:

router.register(r'companies/(?P<iso_country>[^/.]+)/', YourCompanyViewSet, 'company-base')

您必须在ViewSet中将slug定义为lookup_field

然后,例如,您的类看起来像

class YourCountryViewSet(GenericViewSet):
     lookup_field = 'slug'

    def create(self, request, iso_country):
        ...

    def retrieve(self, request, iso_country, slug):
        ...

答案 2 :(得分:0)

针对这个主题测试了几个答案,并决定将这些答案编译成这种方法:

(这是使用 Permission 中的 django.contrib.auth.models 模型的示例)

"""
Example serializers
"""

from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
from rest_framework import serializers


class ContentTypeReadSerializer(serializers.ModelSerializer):
    """
    ContentType read serializer
    """
    app_label = serializers.CharField(read_only=True, max_length=100)
    model = serializers.CharField(read_only=True, max_length=100)

    class Meta:
        model = ContentType
        fields = '__all__'


class PermissionReadSerializer(serializers.ModelSerializer):
    """
    Permission read serializer
    """
    name = serializers.CharField(read_only=True, max_length=255)
    content_type = ContentTypeReadSerializer(read_only=True)
    codename = serializers.CharField(read_only=True, max_length=100)

    class Meta:
        model = Permission
        fields = '__all__'


"""
Viewsets mixins
"""

from rest_framework.generics import get_object_or_404


class MultipleLookupFieldsMixin(object):
    """
    Multiple lookup fields mixin
    """
    lookup_fields = None

    def filter_queryset(self, queryset):
        queryset = super().filter_queryset(queryset)
        filters = {}
        for field in self.lookup_fields:
            if field in self.kwargs:
                if self.kwargs[field] != '':
                    filters[field] = self.kwargs[field]
        if len(filters) == 0:
            return queryset
        return queryset.filter(**filters)
      

"""
Example views
"""

from django.contrib.auth.models import Permission
from rest_framework import viewsets
from common.viewsets import MultipleLookupFieldsMixin
from . import serializers


class PermissionViewSet(MultipleLookupFieldsMixin,
                        viewsets.mixins.ListModelMixin,
                        viewsets.mixins.RetrieveModelMixin,
                        viewsets.GenericViewSet):
    """
    Permission viewset
    """
    queryset = Permission.objects.all()
    serializer_class = serializers.PermissionReadSerializer
    lookup_fields = ['content_type__app_label', 'codename']
    lookup_field = 'codename'


"""
Example urls
"""

from django.conf.urls import url, include
from rest_framework.routers import SimpleRouter
from . import views


router = SimpleRouter()
router.register(r'permission/?(?P<content_type__app_label>\w+|)', views.PermissionViewSet, basename='permission')


urlpatterns = [
    url(r'', include(router.urls)),
]

通过这种方法,您可以拥有 3 个工作端点:

/permission/
/permission/{content_type__app_name}/
/permission/{content_type__app_name}/{codename}/

尽管如此,这只是专用嵌套路由库(如 drf-nested-routers

)的一种替代方案