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层
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
序列化用法:
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()
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
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
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
3. 定义方法(推荐)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
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
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
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')])]
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
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请求参数名
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
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
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
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从大到小排列
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
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
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
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'})), ]
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
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("查询")