Django Rest Framework,具有多个Viewset和Routers,用于同一对象

Ben*_* RR 7 python django rest django-rest-framework

我无法使用Django Rest Framework为同一个对象定义不同的视图集.以下是基于DRF快速入门重现问题的最小示例.我使用的是python 3.5和最新的DRF.

教程/快速启动/ serializers.py

from django.contrib.auth.models import User
from rest_framework import serializers


class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('url', 'username', 'email')

class UserMinimalSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('url', 'username')
Run Code Online (Sandbox Code Playgroud)

教程/快速启动/ views.py

from django.contrib.auth.models import User
from rest_framework import viewsets
from tutorial.quickstart.serializers import UserSerializer, UserMinimalSerializer

class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all().order_by('-date_joined')
    serializer_class = UserSerializer


class UserMinimalViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all().order_by('-date_joined')
    serializer_class = UserMinimalSerializer
Run Code Online (Sandbox Code Playgroud)

教程/ urls.py

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

router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'users-minimal', views.UserMinimalViewSet) 

urlpatterns = [
    url(r'^', include(router.urls))
]
Run Code Online (Sandbox Code Playgroud)

运行服务器并获取根目录时,最终得到:

HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "users": "http://127.0.0.1:8000/users-minimal/",
    "users-minimal": "http://127.0.0.1:8000/users-minimal/"
}
Run Code Online (Sandbox Code Playgroud)

注意usersusers-minimal指向.../users-minimal/.

此外,访问时,http://HOST:PORT/users/您将获得:

HTTP 200 OK
Allow: GET, POST, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "count": 2,
    "next": null,
    "previous": null,
    "results": [
        {
            "url": "http://127.0.0.1:8000/users-minimal/2/",
            "username": "user2",
            "email": "user2@users.com"
        },
        {
            "url": "http://127.0.0.1:8000/users-minimal/1/",
            "username": "user1,
            "email": "user1@users.com"
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

请注意网址指向.../users-minimal/.

最后说明:我的问题与问题有些类似,但建议的解决方案对我不起作用,也没有说明为什么它应该首先起作用.

Dan*_*tar 8

简答:您必须将basename参数添加到您的路线users-minimal:

router = routers.DefaultRouter()
router.register(r'users', UserViewSet)
router.register(r'users-minimal', UserMinimalViewSet, basename='usersminimal')
Run Code Online (Sandbox Code Playgroud)

通常情况下,DRF会basename自动生成一个queryset.这在DRF路由器文档中进行了解释,搜索basename.

你的两个Viewset使用相同,queryset所以最初是相同的basename.这导致了你所看到的问题,后来注册的ViewSet将覆盖前注册的路由ViewSet.当您更改router.register示例中的顺序时,您可以看到此操作.

在shell中直接测试代码时,可以看到路由的基本名称:

from rest_framework import routers
from tutorial.quickstart import views

router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'users-minimal', views.UserMinimalViewSet)


> routers.urls
[<RegexURLPattern user-list ^minimal/$>,
<RegexURLPattern user-list ^minimal\.(?P<format>[a-z0-9]+)/?$>,
<RegexURLPattern user-detail ^minimal/(?P<pk>[^/.]+)/$>,
<RegexURLPattern user-detail ^minimal/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$>,
<RegexURLPattern user-list ^users/$>,
<RegexURLPattern user-list ^users\.(?P<format>[a-z0-9]+)/?$>,
<RegexURLPattern user-detail ^users/(?P<pk>[^/.]+)/$>,
<RegexURLPattern user-detail ^users/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$>,
<RegexURLPattern api-root ^$>,
<RegexURLPattern api-root ^\.(?P<format>[a-z0-9]+)/?$>]
Run Code Online (Sandbox Code Playgroud)