美文网首页
rest_framework 路由器

rest_framework 路由器

作者: eeert2 | 来源:发表于2020-03-01 11:44 被阅读0次

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/ 可以进行getputpatchdelete请求

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
    同时必须实现listupdatecreate等方法。

# `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模型名称[小写]加后缀listdetail, 自动生成视图名称
    这里我们的modelUserInfo,所以生成的nameuserinfo-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返回的就是djangourlpatterns列表,我们完全可以把它和django同时使用

example 2. djangorest_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. 使用djangoinclude功能

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_fieldlookup_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

    ……

如上,对UserViewSetrest_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路径后面,这个必须设置True or False,设置为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 使用

DefaultRouterSimpleRouter的加强版,用法和SimpleRouter完全一样,但是DefaultRouter有两个优点

    1. DefaultRouter会自动生成一个根路径,列出了所有视图的超链接
    1. 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}
]

相关文章

网友评论

      本文标题:rest_framework 路由器

      本文链接:https://www.haomeiwen.com/subject/aagtkhtx.html