DRF序列化组件
1.DRF序列化器Serializer
models.py:
from django.db import models class UserInfo(models.Model): """ 用户表 """ user_type_choices = [ (1, '普通用户'), (2, 'VIP用户'), (3, 'SVIP用户'), ] user_type = models.IntegerField(choices=user_type_choices) username = models.CharField(max_length=10, unique=True) password = models.CharField(max_length=12, null=False) group = models.ForeignKey(to='UserGroup') role = models.ManyToManyField(to='UserRole') class UserToken(models.Model): """ token表 """ user = models.OneToOneField(to='UserInfo') token = models.CharField(max_length=64) create_time = models.DateTimeField(auto_now=True) class UserGroup(models.Model): title = models.CharField(max_length=10) class UserRole(models.Model): role = models.CharField(max_length=12)
urls.py
drf主路由配置urls.py:
from django.conf.urls import url,include urlpatterns = [ url(r'^api/', include('api.urls')), ]
api路由配置urls.py:
from django.conf.urls import url from api import views urlpatterns = [ url(r'^(?P<version>v[\d+])/users/', views.UsersView.as_view(), name='users'), url(r'^(?P<version>v[\d+])/parsers/', views.ParsersView.as_view(), name='parsers'), url(r'^(?P<version>v[\d+])/userroles/', views.UserRole.as_view(), name='userrole'), url(r'^(?P<version>v[\d+])/userinfos/', views.UserInfoView.as_view(), name='userinfo'), ]
views.py:
from django.shortcuts import render, HttpResponse from rest_framework.views import APIView from rest_framework.versioning import BaseVersioning, QueryParameterVersioning, URLPathVersioning from django.urls import reverse from rest_framework.parsers import JSONParser, FormParser, MultiPartParser, FileUploadParser from django.http.response import JsonResponse from rest_framework import serializers from api import models import json class UsersView(APIView): # API版本组件(局部配置)----返回结果都是一样 # 也需要在settings.py中的REST_FRAMEWORK进行全局配置 ''' default_version = api_settings.DEFAULT_VERSION allowed_versions = api_settings.ALLOWED_VERSIONS version_param = api_settings.VERSION_PARAM ''' # (1)当版本号以查询参数形式传递时:比如:http://127.0.0.1:8000/api/users/?version=v1 # (推荐第2种方式,此方式url(r'^/users/',views.UsersView.as_view(),name='users'),) # versioning_class = QueryParameterVersioning # (2)当版本号以路径urlpath形式传递时:比如:http://127.0.0.1:8000/api/v1/users/ # (注意在urls.py中使用正则匹配url(r'^(?P<version>v[\d+])/users/',views.UsersView.as_view(),name='users'),) # versioning_class = URLPathVersioning def get(self, request, *args, **kwargs): print(request.version) # 获取版本号 print(request.versioning_scheme) # 获取到版本号处理的类对象,封装了reverse方法 print(request.versioning_scheme.reverse(viewname='users', request=request)) # 反向解析url # print(reverse(viewname='users',kwargs={'version':request.version}))#django原生解析,必须指定参数 return HttpResponse('get_users') def post(self, request, *args, **kwargs): return HttpResponse('post_user') class ParsersView(APIView): # 解析器组件(局部配置)----不配置默认全都支持 parser_classes = [FormParser] ''' from rest_framework.parsers import JSONParser,FormParser,MultiPartParser,FileUploadParser JSONParser:'application/json' FormParser:'application/x-www-form-urlencoded' MultiPartParser:'multipart/form-data' FileUploadParser:'*/*' ''' def post(self, request, *args, **kwargs): print(request.POST) # 1.获取请求 print(request.data) return HttpResponse('DRF解析器测试') # (1)自定义序列化器继承serializers.Serializer的简单使用 class UserRoleSerializer(serializers.Serializer): ''' 角色序列化器 ''' pk = serializers.IntegerField() role = serializers.CharField() class UserRole(APIView): ''' 自定义序列化器的简单使用 ''' def get(self, request, *args, **kwargs): ''' 显示所有的角色信息,以字符串形式返回 :param request: :param args: :param kwargs: :return: ''' # 方式一:手动序列化 ''' #json不能序列化django中的QuerySet类型数据,需要转换python支持的数据类型在序列化 ret = models.UserRole.objects.all().values('pk','role') ret =json.dumps(list(ret),ensure_ascii=False) ''' # 方式二:drf中的序列化器组件 query_set = models.UserRole.objects.all() ret_serializer = UserRoleSerializer(instance=query_set, many=True) # 序列化多条数据时指定many=True,单条数据指定many=False # query_set = models.UserRole.objects.all().first() # ret_serializer = UserRoleSerializer(instance=query_set, many=False) ret = json.dumps(ret_serializer.data, ensure_ascii=False) return HttpResponse(ret) # (2)自定义序列化器继承serializers.Serializer的详解 class UserInfoSerializer(serializers.Serializer): # (1)序列化表中对应的字段,字段名要和表字段对应 # user_type = serializers.IntegerField() #显示表中存储的数字 username = serializers.CharField() # password = serializers.CharField() # (2)序列化表中的choice字段,需要使用source参数结合get_field_display方法(方法会自动调用) user_type = serializers.CharField(source="get_user_type_display") # (3)使用表中不存在字段来序列化表字段时需要使用source参数指定源数据 pwd = serializers.CharField(source="password") # (4)序列化外键字段(多对一)使用source参数指定源数据(外键字段的.方法) group = serializers.CharField(source="group.title") # (5)序列化多对多字段(数据多个需要使用) role = serializers.SerializerMethodField() def get_role(self, instance): # 第二个参数instance是当前对象 query_set = instance.role.all() ret = [{'pk': obj.pk, 'role': obj.role} for obj in query_set] return ret class UserInfoView(APIView): def get(self, requeat, *args, **kwargs): query_set = models.UserInfo.objects.all() ret_serializer = UserInfoSerializer(instance=query_set, many=True)# 序列化多条数据时指定many=True,单条数据指定 ret = ret_serializer.data return JsonResponse(ret, safe=False, json_dumps_params={'ensure_ascii': False}) # 序列化时确保中文正常显示
settings.py
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'api.apps.ApiConfig', 'rest_framework', ] REST_FRAMEWORK = { #版本组件(全局配置)----在认证+权限+节流之前 'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning',#设置版本组件类 'DEFAULT_VERSION':'v1',#默认的API版本 'ALLOWED_VERSIONS':['v1','v2'],#允许的API版本 'VERSION_PARAM':'version',#版本的key,默认的就是version(注意要和api接口中的key对应) #解析器组件 'DEFAULT_PARSER_CLASSES':['rest_framework.parsers.JSONParser','rest_framework.parsers.FormParser',],#可指定多个解析器,不配置默认支持所有 }
2. DRF序列化器ModelSerializer
基于上述的案例实现 # 自定义序列化器继承serializers.Serializer的详解 ''' class UserInfoSerializer(serializers.Serializer): # (1)序列化表中对应的字段,字段名要和表字段对应 # user_type = serializers.IntegerField() #显示表中存储的数字 username = serializers.CharField() # password = serializers.CharField() # (2)序列化表中的choice字段,需要使用source参数结合get_field_display方法 user_type = serializers.CharField(source="get_user_type_display") # (3)使用表中不存在字段来序列化表字段时需要使用source参数指定源数据 pwd = serializers.CharField(source="password") # (4)序列化外键字段(多对一)使用source参数指定源数据(外键字段的.方法) group = serializers.CharField(source="group.title") # (5)序列化多对多字段(数据多个需要使用) role = serializers.SerializerMethodField() def get_role(self, instance): # 第二个参数instance是当前对象 query_set = instance.role.all() ret = [{'pk': obj.pk, 'role': obj.role} for obj in query_set] return ret ''' #自定义序列化器继承serializers.ModelSerializer类(基于model表对象实现) class UserInfoSerializer(serializers.ModelSerializer): # (1)定义元类Meta指定model和fields,自动映射表中的字段,还可自定义字段 class Meta: model= models.UserInfo#指定model表对象 # fields = "__all__"#设置所有字段 fields = ['pk','user_type','username','pwd','group_title','role_list']#指定字段(可以定制) # (2)表中choice字段 user_type = serializers.CharField(source='get_user_type_display') # (3)表中字段修改名 pwd = serializers.CharField(source='password') # (4)外键多对一字段 group_title = serializers.CharField(source='group.title') # (5)多对多的多字段 role_list = serializers.SerializerMethodField() def get_role_list(self, instance): # 第二个参数instance是当前对象 query_set = instance.role.all() ret = [{'pk': obj.pk, 'role': obj.role} for obj in query_set] return ret class UserInfoView(APIView): def get(self, requeat, *args, **kwargs): query_set = models.UserInfo.objects.all() ret_serializer = UserInfoSerializer(instance=query_set, many=True)# 序列化多条数据时指定many=True,单条数据指定many=False ret = ret_serializer.data return JsonResponse(ret, safe=False, json_dumps_params={'ensure_ascii': False}) # 序列化时确保中文正常显示
3.DRF序列化器depth深度序列化
DRF序列化器ModelSerializer基于参数depth深度序列化
#自定义序列化器继承serializers.ModelSerializer类(基于model表对象实现,集合参数depth实现表关联字段的的数据序列化) class UserInfoSerializer(serializers.ModelSerializer): class Meta: model= models.UserInfo#指定model表对象 # fields = "__all__"#设置所有字段 fields = ['pk','user_type','username','password','group','role']#指定字段(可以定制) depth = 1#序列化深度指定,默认为0,建议在0-10,可以深度序列化表字段数据 class UserInfoView(APIView): def get(self, requeat, *args, **kwargs): query_set = models.UserInfo.objects.all() ret_serializer = UserInfoSerializer(instance=query_set, many=True) ret = ret_serializer.data return JsonResponse(ret, safe=False, json_dumps_params={'ensure_ascii': False}) # 序列化时确保中文正常显示
4.DRF序列化器返回url链接
遵循RESTful规范中的Hypermedia API(返回有带url结果)
urls.py
drf主路由配置urls.py:
from django.conf.urls import url,include urlpatterns = [ url(r'^api/', include('api.urls')), ]
api路由配置urls.py:
from django.conf.urls import url from api import views #版本控制组件在settings.py中 urlpatterns = [ url(r'^(?P<version>v[\d+])/userinfos/', views.UserInfoView.as_view(), name='userinfo'), url(r'^(?P<version>v[\d+])/group/(?P<pk>\d+)/', views.UserGroupView.as_view(), name='group'), ]
views.py:
from rest_framework.views import APIView from django.http.response import JsonResponse from rest_framework import serializers from api import models # 自定义序列化器继承serializers.ModelSerializer类(在序列化结果中返回url) class UserInfoSerializer(serializers.ModelSerializer): # # 指定别名和参数lookup_url_kwarg以及参数对应的值lookup_field,通过反向解析生成,在使用序列化器时必须加上参数,context={'request': request} #view_name是别名,lookup_field是指定的值,lookup_url_kwarg指定的参数 group = serializers.HyperlinkedIdentityField(view_name='group',lookup_field='group_id',lookup_url_kwarg='pk') class Meta: model = models.UserInfo fields = ['pk', 'user_type', 'username', 'password', 'group', 'role'] depth = 1 class UserInfoView(APIView): def get(self, request, *args, **kwargs): query_set = models.UserInfo.objects.all() # 注意在序列化器中使用HyperlinkedIdentityField是必须在序列化时加上context={'request': request} ret_serializer = UserInfoSerializer(instance=query_set, many=True, context={'request': request}) ret = ret_serializer.data return JsonResponse(ret, safe=False, json_dumps_params={'ensure_ascii': False}) # 序列化时确保中文正常显示 class UserGroupSerializer(serializers.ModelSerializer): class Meta: model = models.UserGroup fields = "__all__" class UserGroupView(APIView): def get(self, request, *args, **kwargs): pk = kwargs.get('pk') obj = models.UserGroup.objects.filter(pk=pk).first() ret_serializer = UserGroupSerializer(instance=obj, many=False) ret = ret_serializer.data return JsonResponse(ret, safe=False, json_dumps_params={'ensure_ascii': False}) # 序列化时确保中文正常显示
5. DRF序列化器的校验功能
DRF序列化器的校验可以对比form校验来使用,基本类似,也可定义字段的校验,校验参数、自定义函数以及钩子
class UserGroupSerializer(serializers.ModelSerializer): class Meta: model = models.UserGroup fields = "__all__" class UserGroupView(APIView): def get(self, request, *args, **kwargs): pk = kwargs.get('pk') obj = models.UserGroup.objects.filter(pk=pk).first() ret_serializer = UserGroupSerializer(instance=obj, many=False) ret = ret_serializer.data return JsonResponse(ret, safe=False, json_dumps_params={'ensure_ascii': False}) # 序列化时确保中文正常显示 def post(self, request, *args, **kwargs): data = request.data ret = UserGroupSerializer(data=data)#基于序列化器的校验 if ret.is_valid(): print(ret.validated_data) else: print(ret.errors) return JsonResponse(data)
数据校验 基本校验 class Parent(serializers.Serializer): # required 这个字段是否必传 # allow_blank 是否允许这个字段为 空值 # allow_null 是否允许这个字段为 null值 #定义error_messages={},validators=[]进行错误处理和校验,类比form value = serializers.CharField(required=True, allow_blank=True, allow_null=True) 钩子校验 class Child(serializers.Serializer): name = serializers.CharField(required=True) # 数据校验之前 可以获取到原始数据的方法 def to_internal_value(self, data): return data # 局部钩子 def validate_name(self, value): return value # 全局钩子 def validate(self, data): return data class Parent(serializers.Serializer): value = serializers.CharField(required=True, allow_blank=True, allow_null=True) children = serializers.ListSerializer(child=Child()) $ data = {"value": "sdf", "children": [{"name": "", }, {"name": "哈哈哈"}]} $ ser = Parent(data=data) $ ser.is_valid() False $ ser.errors {'children': [{'name': [ErrorDetail(string='This field may not be blank.', code='blank')]}, {}]} $ data = {"children": [{"name": "", }, {"name": "哈哈哈"}]} $ ser = Parent(data=data) $ ser.is_valid() False $ ser.errors {'value': [ErrorDetail(string='This field is required.', code='required')], 'children': [{'name': [ErrorDetail(string='This field may not be blank.', code='blank')]}, {}]}
6.DRF序列化器的嵌套
序列化器嵌套示例
# 针对于 多对多 数据 正向反向的数据操作 from rest_framework import serializers data = {'id': 1, 'children': [{'id': 2}, {'id': 3}]} class Child(serializers.Serializer): id = serializers.IntegerField() class Parent(serializers.Serializer): id = serializers.IntegerField() children = serializers.ListSerializer(child=Child())#子序列化器 ''' # 另一种写法 class Parent(serializers.Serializer): id = serializers.IntegerField() childs = Child(many=True, source='children')#表中的指向的多字段 ''' print(Parent(data).data)
序列化嵌套应用
class SurveyChoiceSerializer(serializers.ModelSerializer): class Meta: model = models.SurveyChoice fields = "__all__" class SurveyQuestionSerializer(serializers.ModelSerializer): # 第一种方式 # choices = serializers.SerializerMethodField() # def get_choices(self, instance): # return list(instance.surveychoice_set.values()) # 第二种方式 choices = SurveyChoiceSerializer(many=True, source="answers")#多对多的字段 value = serializers.CharField(default="") class Meta: model = models.SurveyQuestion fields = ( "id", "survey_type", "title", "choices", "value", ) class SurveyTemplateSerializer(serializers.ModelSerializer): # 层层递交 questions = SurveyQuestionSerializer(many=True) class Meta: model = models.SurveyTemplate fields = ( "id", "name", "questions", ) class SurveyDetailSerializer(serializers.ModelSerializer): # 交给子级序列化器渲染 survey_templates = serializers.ListSerializer(child=SurveyTemplateSerializer()) class Meta: model = models.Survey fields = ( "id", "survey_templates", )