首页 > 技术文章 > Djangorestframework

hello-kiki 2019-11-23 16:45 原文

 

序列化
验证
解析器
授权和权限
版本控制
分页
视图和路由
访问频率

djangorestframework模块为django提供了restful接口

安装 : pip install djangorestframework
    django settings.py   INSTALLED_APPS 中加入 "rest_framework"

 

序列化

序列化是该模块的最基本功能,能够将表数据,转换为json字典以及json字符串

形式1

复制代码
from rest_framework import serializers 

class UserSerializer(serializers.Serializer):
    ut_title = serializers.CharField(source='ut.title')
    user = serializers.CharField(min_length=6)
    pwd = serializers.CharField(error_messages={'required': '密码不能为空'}, validators=[PasswordValidator()])
   x1 = serializers.CharField(source='group.mu.name') # 多对一或一对一跨表查询
 
    def create(self, validated_data):
        """
        根据提供的验证过的数据创建并返回一个新的`Snippet`实例。用于保存
        """
        return Userinfo.objects.create(**validated_data)

    def update(self, instance, validated_data):
        """
        根据提供的验证过的数据更新和返回一个已经存在的`Snippet`实例。
        """
        instance.ut_title= validated_data.get('ut_title', instance.ut_title)
        instance.user= validated_data.get('user', instance.user)
        instance.pwd = validated_data.get('pwd', instance.pwd)
        instance.save()
        return instance
# 自定义序列化 # 这种形式类似于django的form组件

形式2

class UserSerializer(serializers.ModelSerializer):
    """序列化类"""

    class Meta:
        model = models.Register
        fields = "__all__"
         depth=1#这里表示序列化的深度,建议不要超过3层

 

 对多对多以及自定义字段的处理

序列化用法:

views.py中

 保存

snippet = Snippet(ut_title="abc",user="abc",pwd= "abcd')
snippet.save()

读取:

serializer = SnippetSerializer(instance=对象,many=True) # many=True 决定instance对象是集合还是单独obj
serializer.data

转化为json字符串

from rest_framework.renderers import JSONRenderer

content = JSONRenderer().render(serializer.data) # json字符串

反序列化

from rest_framework.parsers import JSONParser
from django.utils.six import BytesIO

stream = BytesIO(content)
data = JSONParser().parse(stream)

 

多对多序列化处理有三种方式:

1. 从新定义CharField()

复制代码
class TempCharField(serializers.CharField):
    def to_representation(self, value): # 打印的是所有的数据
        data_list = []
        for row in value:
            data_list.append(row.name)
        return data_list

class UsersSerializer(serializers.Serializer):
    # a = serializers.CharField(source="roles.all") #  多对多关系的这样查出的是queryset对象
    a = TempCharField(source="roles.all") 
复制代码

2. 定义child

复制代码
class MyCharField(serializers.CharField):
    def to_representation(self, value):
        return {'id':value.pk, 'name':value.name}

class UsersSerializer(serializers.Serializer):
    # a = serializers.CharField(source="roles.all") # obj.mu.name
    a2 = serializers.ListField(child=MyCharField(),source="roles.all") 
复制代码

3. 定义方法(推荐)

复制代码
class UsersSerializer(serializers.Serializer):
    # a = serializers.ListField(child=MyCharField(),source="roles.all") # obj.mu.name
    a3 = serializers.SerializerMethodField()
    def get_a3(self,obj):  #get_字段名
        print(obj)   # object
        obj.roles.all()
        role_list = obj.roles.filter(id__gt=1)
        data_list = []
        for row in role_list:
            data_list.append({'pk':row.pk,'name':row.name})
        return data_list
复制代码

 

反向生成url

复制代码
class UserSerializer(serializers.ModelSerializer):
    bbb = serializers.HyperlinkedIdentityField(view_name='detail')  #让bbb的结果为按照urls中name为detail的url反向生成url
    class Meta:
        model = models.BBB
        fields = ["b","bb","bbb"]
        depth = 1

class A(APIView):
    def get(self, request, *args, **kwargs):
        user = models.BBB.objects.all()
        print(UserSerializer(instance=user,many=True,context={'request':request}).data)
        return HttpResponse("111")



#url.py
url(r'^users5/(?P<pk>.*)', views.BBB.as_view(), name='detail')

# 结果:
[OrderedDict([('b', 'b1'), ('bb', 'b2'), ('bbb', 'http://127.0.0.1:8000/a/1')]), OrderedDict([('b', 'b2'), ('bb', 'b3'), ('bbb', 'http://127.0.0.1:8000/a/2')])]
复制代码

 

复制代码
class UsersSerializer(serializers.HyperlinkedModelSerializer): #继承他自动生成
    class Meta:
        model = models.UserInfo
        fields = "__all__"
        exclude=["aaa"]  # 排除某个字段


class UsersView(APIView):
    def get(self,request,*args,**kwargs):
        # 方式一:
        # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
        # return Response(user_list)

        # 方式二之多对象
        user_list = models.UserInfo.objects.all()
        ser = UsersSerializer(instance=user_list,many=True,context={'request':request})
        return Response(ser.data)


 url.py
     url(r'^aa/(?P<pk>\)$', aaa.MicroView.as_view(),name="ser_detail") # 默认name为字段名+detail
复制代码

 

Ⅳ 解析器

除了直接用url发get请求,我们还有post请求,还有url参数。restframework组件提供了更方便的功能处理各种请求数据

from rest_framework.parsers import FormParser,JSONParser,FileUploadParser,MultiPartParser 
以上四个模块分别用来处理【application/x-www-form-urlencoded】,【application/json】,【multipart/form-data】,【文件上传】,把相关内容赋值给request.da

 全局配置

REST_FRAMEWORK = {

    'DEFAULT_PARSER_CLASSES': [
        'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.FormParser',  # 解析器配置
        'rest_framework.parsers.MultiPartParser'
    ],

}

视图使用

username = request.data.get('username')

 

Ⅴ 认证&权限

django restframework还在django auth模块的基础上集成了认证和权限模块,方便客户登陆,并对访问进行限制

其中认证模块主要的功能是确认客户端身份并,并将身份赋值给相关变量(BaseAuthentication)

权限模块是通过相关变量拿到客户端身份,并对该身份客户的请求进行限制()

5.1 认证

5.1.1 基本模式

全局配置

REST_FRAMEWORK = {

    'DEFAULT_PARSER_CLASSES': [
        'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.FormParser',  # 解析器配置
        'rest_framework.parsers.MultiPartParser'
    ],
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "api.utils.Authentication.MyAuthentication",  # 认证配置
    ],


}

认证类

from rest_framework import exceptions
from rest_framework.authentication import BaseAuthentication
from rest_framework.permissions import BasePermission
from rest_framework.throttling import SimpleRateThrottle
from api import models


class MyAuthentication(BaseAuthentication):
    """认证类"""

    def authenticate(self, request):
        token = request.query_params.get('token')

        obj = models.UserToken.objects.filter(token=token).first()
        if not token:
                raise exceptions.AuthenticationFailed("认证失败")
        return (obj.user.username,token)

    def authenticate_header(self, request):
        pass

局部不使用

class UserView(APIView):
    """登录用户查询"""

     authentication_classes = []  # 免除认证

 

5.2 权限

全局使用

REST_FRAMEWORK = {
"DEFAULT_PERMISSION_CLASSES": [
"api.utils.Authentication.TestPermission", # 权限配置
],

}

权限类

class TestPermission(BasePermission):
    """权限类"""

    def has_permission(self, request, view):
#在这里可以加自己的逻辑
return True

局部不使用

 permission_classes = []#免除权限认证

 

Ⅵ 版本控制

全局配置

REST_FRAMEWORK = {
     'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning",
     'DEFAULT_VERSION': 'v1',            # 默认版本
     'ALLOWED_VERSIONS': ['v1', 'v2'],   # 允许的版本
     'VERSION_PARAM': 'version', 
}

局部视图使用

class LogonViews(APIView):
    versioning_class = URLPathVersioning#配置版本类
    def get(self, request, *args, **kwargs):
        request.version#获取版本
        print(request.data.get("username"))
        return HttpResponse("查询")
  

Url格式

  

from django.urls import path, re_path
from api import views

urlpatterns = [
    re_path(r'^(?P<version>[v1|v2]+)/logon/',views.LogonViews.as_view()),
    re_path(r'^(?P<version>[v1|v2]+)/user/', views.UserView.as_view()),
    re_path(r'^(?P<version>[v1|v2]+)/seek/', views.SeekViews.as_view()),
    # path('word',views.WordViews.as_view()),

]

  

 

 高级部分

  基于以上部分,小伙伴们已经基本可以写出restful 的后端。但是restframework为我们解决的不仅仅只有这些!

 Ⅶ 分页

 7.1 LimitOffsetPagination

from rest_framework.pagination import LimitOffsetPagination
class LP(LimitOffsetPagination):
    max_limit = 40  # 最大每页显示的条数
    default_limit =20  # 默认每页显示的条数
    limit_query_param = 'limit'  # 往后取几条,get请求参数名
    offset_query_param = 'offset'  # 当前所在的位置,get请求参数名
复制代码
class UserViewSet(APIView):
    def get(self, request, *args, **kwargs):
        user_list = models.UserInfo.objects.all()
        # 实例化分页对象,获取数据库中的分页数据
        paginator = LP()
        page_user_list = paginator.paginate_queryset(user_list, self.request, view=self)

        # 序列化对象
        serializer = UserSerializer(page_user_list, many=True)

        # 生成分页和数据
        response = paginator.get_paginated_response(serializer.data)
        return response
复制代码

 

 

7.2 PageNumberPagination

from rest_framework.pagination import PageNumberPagination

复制代码
from rest_framework.pagination import PageNumberPagination

class StandardResultsSetPagination(PageNumberPagination):
    # 默认每页显示的数据条数
    page_size = 1
    # 获取URL参数中设置的每页显示数据条数
    page_size_query_param = 'page_size'
    # 获取URL参数中传入的页码key
    page_query_param = 'page'
    # 最大支持的每页显示的数据条数
    max_page_size = 1
复制代码
复制代码
class UserViewSet(APIView):
    def get(self, request, *args, **kwargs):
        user_list = models.UserInfo.objects.all().order_by('-id')
        # 实例化分页对象,获取数据库中的分页数据
        paginator = StandardResultsSetPagination()
        page_user_list = paginator.paginate_queryset(user_list, self.request, view=self)

        # 序列化对象
        serializer = UserSerializer(page_user_list, many=True)

        # 生成分页和数据
        response = paginator.get_paginated_response(serializer.data)
        return response
复制代码

 

 7.3 CursorPagination

from rest_framework.pagination import CursorPagination

复制代码
from rest_framework.pagination import CursorPagination
class CP(CursorPagination): cursor_query_param = 'cursor' # URL传入的游标参数 page_size = 2 # 默认每页显示的数据条数 page_size_query_param = 'page_size' # URL传入的每页显示条数的参数 max_page_size = 1000 # 每页显示数据最大条数 ordering = "id" # 根据ID从大到小排列
复制代码
复制代码
class UserViewSet(APIView):
    def get(self, request, *args, **kwargs):
        user_list = models.UserInfo.objects.all().order_by('-id')

        # 实例化分页对象,获取数据库中的分页数据
        paginator = CP()
        page_user_list = paginator.paginate_queryset(user_list, self.request, view=self)

        # 序列化对象
        serializer = UserSerializer(page_user_list, many=True)
        # 生成分页和数据
        response = paginator.get_paginated_response(serializer.data)
        return response
复制代码

 

Ⅷ 视图 & 路由

除了最基本的APIView, restframework还为我们提供了GenericViewSet,ModelViewSet,ModelViewSet三个视图实现方案

8.1 GenericViewSet

复制代码
from django.conf.urls import url, include

urlpatterns = [
    url(r'test/', TestView.as_view({'get':'list'}), name='test'),
    url(r'detail/(?P<pk>\d+)/', TestView.as_view({'get':'list'}), name='xxxx'),  
]  
# 这里会为每一种请求设置一个视图函数,例如为get设置一个叫list的视图函数
复制代码
from rest_framework import viewsets
class TestView(viewsets.GenericViewSet):
    def list(self, request, *args, **kwargs):  # get请求会找这个方法
        return Response('...')

 

8.2 ModelViewSet

复制代码
from django.conf.urls import url, include
from web.views import s10_generic

urlpatterns = [
    url(r'^test/$', s10_generic.UserViewSet.as_view({'get': 'list', 'post': 'create'})),
    url(r'^test/(?P<pk>\d+)/$', s10_generic.UserViewSet.as_view(
        {'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'})),
]
复制代码
复制代码
from rest_framework.viewsets import ModelViewSet
from rest_framework import serializers
from .. import models


class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.UserInfo
        fields = "__all__"


class UserViewSet(ModelViewSet):
    queryset = models.UserInfo.objects.all()
    serializer_class = UserSerializer
复制代码

 

8.3 路由系统

配合ModelViewSet,路由系统可以帮我们省去写路由的繁琐,可以自动实现增删改查

复制代码
from django.conf.urls import url, include
from rest_framework import routers
from app01 import views

router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'groups', views.GroupViewSet)

# Wire up our API using automatic URL routing.
# Additionally, we include login URLs for the browsable API.
urlpatterns = [
    url(r'^', include(router.urls)),
]
复制代码

 

 

Ⅹ 访问频率

全局配置

REST_FRAMEWORK = {
     
    "DEFAULT_THROTTLE_CLASSES": [  # 节流配置
        "api.utils.Authentication.Throttlings"#节流类的路径
    ],
    'DEFAULT_THROTTLE_RATES': {
        'user1': '5/m',
        'visit': '10/m',
    },
    "UNAUTHENTICATED_USER": lambda: '匿名用户',

节流类

class VisitThrottlings(SimpleRateThrottle):
    """节流类,匿名用户
    """
    scope = "visit"
    def get_cache_key(self, request, view):
        return self.get_ident(request)  # 设置控制标识,根据ip进行节流


class Throttlings(SimpleRateThrottle):
    """节流类,登录用户"""
    scope = "user1"
    def get_cache_key(self, request, view):
        return request.user  # 设置控制标识,根据用户名进行节流

视图使用

class LogonViews(APIView):
    throttle_classes =[VisitThrottlings,]#设置节流类
    def get(self, request, *args, **kwargs):
      
        return HttpResponse("查询")

  

  

 

推荐阅读