rest_framework的路由器是为django的路由系统服务的,不使用rest_framework的路由器我们一样能正常工作,它只是帮助我们去完成urls的匹配工作,减少我们手写urls的时间。
rest_framework的路由器基于通用视图,你需要了解通用视图的知识:
https://www.jianshu.com/p/c7543e0cff05
一、rest_framework路由器自动绑定请求方法与函数
在通用视图中,我们这样去实现请求方法与函数的绑定
urlpatterns = [
path('api/users/', views.UserInfoView.as_view({'get': 'list', 'post': 'create', })),
path('api/user/<int:pk>/', views.UserInfoView.as_view(
{
'get': 'retrieve',
'put': 'update',
'patch': 'partial_update',
'delete': 'destroy'
}
)),
]
这样每次写起来很麻烦,rest_framework的路由器帮助我们进行了默认绑定:
对 resources/
mapping={
'get': 'list',
'post': 'create'
}
对 resources/pk/
mapping={
'get': 'retrieve',
'put': 'update',
'patch': 'partial_update',
'delete': 'destroy'
}
example 1. rest_framework路由器实现自动绑定
# models.py
from django.db import models
class UserInfo(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=64)
# views.py
from rest_framework import serializers
from my_app.models import UserInfo
from rest_framework import mixins
from rest_framework.viewsets import GenericViewSet
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = UserInfo
fields = '__all__'
class UserInfoView(GenericViewSet,
mixins.RetrieveModelMixin,
mixins.CreateModelMixin,
mixins.ListModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
):
"""
UserInfoView 继承了 `retrieve`, `create`, `list`,
`update`, `partial_update`, `destroy`函数
"""
queryset = UserInfo.objects.all()
serializer_class = UserSerializer
# urls.py
from my_app import views
from rest_framework import routers
router = routers.SimpleRouter()
router.register('api/users', views.UserInfoView)
urlpatterns = router.urls
访问一个不存在的地址,会提示
404提示.png
可以看出
rest_framework为我们生成了两条url,分别是
^api/users/$ [name='userinfo-list']^api/users/(?P<pk>[^/.]+)/$ [name='userinfo-detail']
对http://127.0.0.1:8000/api/users/,可以进行get请求、post请求
对http://127.0.0.1:8000/api/users/1/ 可以进行get、put、patch、delete请求
rest_framework自动帮助我们把对应url的请求绑定到对象方法上
注意点:
1.router.register()可以传入三个参数,分别是url前缀,ViewSet, view视图名称
-
1.1
url前缀和django中的url路径前缀用法一致 -
1.2
ViewSet要求传入的类必须继承rest_framework.viewsets.ViewSetMixin,这样才能将get分发到list或者retrieve函数上,post分发到create;
同时必须实现list,update,create等方法。
# `GenericViewSet` 继承了`ViewSetMixin` 与 `GenericAPIView`
class UserInfoView(GenericViewSet,
mixins.RetrieveModelMixin,
mixins.CreateModelMixin,
mixins.ListModelMixin,
):
"""
UserInfoView 继承了 `retrieve`, `create`, `list`,
"""
queryset = UserInfo.objects.all()
serializer_class = UserSerializer
如上,ViewSet只实现了retrieve, create, list,对router生成的url也就无法发起delete,update,patch请求。
- 1.3 如无特殊需求,不需要设置
view视图名称,rest_framework会根据我们ViewSet中的model模型名称[小写]加后缀list、detail, 自动生成视图名称。
这里我们的model为UserInfo,所以生成的name为userinfo-list,userinfo-detail
2. router可以注册多个ViewSet.
router = routers.SimpleRouter()
router.register(r'users', UserViewSet)
router.register(r'accounts', AccountViewSet)
urlpatterns = router.urls
3.router.urls返回的就是django的urlpatterns列表,我们完全可以把它和django同时使用
example 2. django与 rest_framework路由器配合使用
from django.urls import path
from my_app import views
from rest_framework import routers
# `django`的 urls
urlpatterns = [
path('api/users/', views.UserInfoView.as_view()),
path('api/book/', views.index),
……
]
router = routers.SimpleRouter()
router.register('api/users', views.UserInfoView)
# `rest_framework` 生成的 urls
rest_urlpatterns = router.urls
urlpatterns += rest_urlpatterns
example 3. 使用django的include功能
urlpatterns = [
url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),
url(r'^api/', include((router.urls, 'app_name'))),
]
4. 控制url生成方式
router生成url一般为:
-
^api/users/$-> list 路径 -
^api/users/(?P<pk>[^/.]+)/$-> detail 路径
其中前缀是由我们自己指定,在detail 路径中,我们也可以不使用pk作为对象的关键字参数。这里需要了解通用视图:https://www.jianshu.com/p/c7543e0cff05
在ViewSet中有两个属性lookup_field 与 lookup_url_kwarg,这两个参数控制者get_object()行为,因为默认的lookup_url_kwarg = pk,所以生成的url为
^api/users/(?P<pk>[^/.]+)/$
class UserInfoView(GenericViewSet,
mixins.RetrieveModelMixin,
mixins.CreateModelMixin,
mixins.ListModelMixin,
):
"""
UserInfoView 继承了 `retrieve`, `create`, `list`,
"""
queryset = UserInfo.objects.all()
serializer_class = UserSerializer
lookup_field = 'username'
lookup_url_kwarg = 'username' # 指定从`url`中取值的关键字
设置lookup_url_kwarg后:
^api/users/(?P<username>[^/.]+)/$
二、rest_framework路由器生成额外的url路径
一般来说,我们通过post,get,put,patch,delete 对资源进行增,查,改,删,但是有的资源,除了这四种常用的操作之外,还有其它各种操作。也就是说,如果一个资源对应十几个 web_api,请求方法不够分怎么办
class UserViewSet(GenericViewSet):
queryset = UserInfo.objects.all()
serializer_class = UserSerializer
def list(self, request, *args, **kwargs):
pass
def retrieve(self, request, *args, **kwargs):
pass
def update(self, request, *args, **kwargs):
pass
def partial_update(self, request, *args, **kwargs):
pass
def destroy(self, request, *args, **kwargs):
pass
def set_password(self, request, *args, **kwargs):
pass
def get_name(self, request, *args, **kwargs):
pass
……
如上,对UserViewSet,rest_framework的路由器会对我们进行默认的请求分配
{
'get': 'retrieve',
'put': 'update',
'patch': 'partial_update',
'delete': 'destroy'
}
但是对于set_password等其它多出来的函数,就需要我们自己进行设置。
from django.urls import path
from my_app import views
from rest_framework import routers
urlpatterns = [
path('api/users/<int:pk>/set_password/', views.UserViewSet.as_view({'post': 'set_password'})),
path('api/users/<int:pk>/get_name/', views.UserViewSet.as_view({'get': 'get_name'})),
……
]
router = routers.SimpleRouter()
router.register('api/users', views.UserInfoView)
rest_urlpatterns = router.urls
urlpatterns = rest_urlpatterns
针对上述情况,rest_framework也提供了一种解决方式。
from rest_framework.viewsets import GenericViewSet
from rest_framework.decorators import action
class UserViewSet(GenericViewSet):
queryset = UserInfo.objects.all()
serializer_class = UserSerializer
@action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf],
url_path='set-password', url_name='set_password')
def set_password(self, request, *args, **kwargs):
pass
……
在action装饰器中
-
methods表示绑定set_password的请求方法 -
detail表示是否添加到detail路径后面,这个必须设置TrueorFalse,设置为False,则生成^api/users/set-password/$ -
url_path是后缀的url路径 -
url_name,是这一条url对应的view_name
这样就会在两条基础url之外自动生成额外的url
^api/users/$ [name='userinfo-list']
^api/users/(?P<pk>[^/.]+)/$ [name='userinfo-detail']
^api/users/(?P<pk>[^/.]+)/get_name/$ [name='userinfo-get-name']
^api/users/(?P<pk>[^/.]+)/set_password/$ [name='userinfo-set-password']
三、DefaultRouter 使用
DefaultRouter 是SimpleRouter的加强版,用法和SimpleRouter完全一样,但是DefaultRouter有两个优点
-
DefaultRouter会自动生成一个根路径,列出了所有视图的超链接
-
-
DefaultRouter自动生成了格式化后缀路由
-
example 1.使用DefaultRouter
# models.py
from django.db import models
class Student(models.Model):
name = models.CharField(max_length=16)
grade_choices = (
(1, '七年级'),
(2, '八年级'),
(3, '九年级'),
)
grade = models.IntegerField(choices=grade_choices, null=False)
class Teacher(models.Model):
name = models.CharField(max_length=16)
course_choices = (
(1, '语文'),
(2, '数学'),
(3, '英语'),
)
# app_serializers.py
from rest_framework import serializers
from my_app.models import Student, Teacher
class StudentSerializer(serializers.ModelSerializer):
class Meta:
model = Student
fields = '__all__'
class TeacherSerializer(serializers.ModelSerializer):
class Meta:
model = Teacher
fields = '__all__'
# views.py
from rest_framework.viewsets import ModelViewSet
from my_app.models import Student, Teacher
from my_app.app_serializers import StudentSerializer, TeacherSerializer
class StudentViewSet(ModelViewSet):
"""
学生资源类
"""
queryset = Student.objects.all()
serializer_class = StudentSerializer
class TeacherViewSet(ModelViewSet):
"""
教师资源类
"""
queryset = Teacher.objects.all()
serializer_class = TeacherSerializer
# urls.py
from my_app import views
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('student', views.StudentViewSet)
router.register('teacher', views.TeacherViewSet)
urlpatterns = router.urls
访问生成的根路由:http://127.0.0.1:8000/,可以看的 DefaultRouter生成的视图超链接列表。
截屏2020-03-0410.22.08.png
点击
http://127.0.0.1:8000/student/
截屏2020-03-0410.25.01.png
我们还可以访问http://127.0.0.1:8000/student.json返回一个json格式化的数据
[
{"id":1,"name":"韩美美","grade":1},
{"id":2,"name":"王雷","grade":2},
{"id":3,"name":"李动","grade":3},
{"id":4,"name":"韩立","grade":2},
{"id":5,"name":"林东","grade":1}
]













网友评论