Django Rest Framework具有针对同一对象的多个视图集和路由器
问题内容:
我在使用Django Rest
Framework为同一对象定义不同的视图集时遇到麻烦。以下是基于DRF快速入门的重现此问题的最小示例。我正在使用python 3.5和最新的DRF。
tutorial / quickstart / 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')
tutorial / quickstart / 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
教程/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))
]
运行服务器并获取根目录时,您将得到以下结果:
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/"
}
请同时注意users
并users-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"
}
]
}
请注意,网址指向.../users-minimal/
。
最后说明:我的问题与此类似,但是建议的解决方案对我不起作用,也没有说明为什么应该首先解决。
问题答案:
简短答案:您必须将basename
参数添加到以下路线users-minimal
:
router = routers.DefaultRouter()
router.register(r'users', UserViewSet)
router.register(r'users-minimal', UserMinimalViewSet, basename='usersminimal')
通常,DRF会basename
从您的计算机中自动生成一个queryset
。在DRF路由器文档中搜索对此进行了说明basename
。
您的两个Viewset
使用相同queryset
的字母,因此最初相同basename
。这就导致了您所看到的问题,后一个注册的ViewSet
将覆盖前一个注册的路由ViewSet
。当您更改router.register
示例中的顺序时,可以看到这一点。
在外壳中直接测试代码时,可以看到路由的基本名称:
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]+)/?$>]