先创建数据库,并添加相应的数据,用来后面序列化使用html
为数据创建相应的数据库模型,而且有一对一,多对多,外键关联。前端
from django.db import models class UserGroup(models.Model): title = models.CharField(max_length=32) 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=32,unique=True) password = models.CharField(max_length=64) group = models.ForeignKey("UserGroup", on_delete=models.CASCADE) roles = models.ManyToManyField("Role") class UserToken(models.Model): user = models.OneToOneField(to='UserInfo', on_delete=models.CASCADE) token = models.CharField(max_length=64) class Role(models.Model): title = models.CharField(max_length=32)
并执行数据库迁移操做python
python manage.py makemigrations python manage.py migrate
当数据迁移执行以后,会在sqlite数据库中生活以下表
sql
多对多关系的时候,django
自动生成第三张表维系表关系,字段分别是userinfo
和role
的id
,其中api_userinfo_roles
为多对多关系生成的表。
在表中添加少许数据数据库
from django.conf.urls import url from .views import RoleView urlpatterns = [ url(r'^role/$', RoleView.as_view()), ]
from rest_framework.views import APIView from .models import Role import json class RoleView(APIView): def get(self, request, *args, **kwargs): roles = Role.objects.all().values('id' ,'title') print(roles, type(roles)) # roles为一个QuerySet对象 ret_roles = json.dumps(list(roles), ensure_ascii=False) # 多条数据 return HttpResponse(ret_roles)
from rest_framework import serializers class RoleSerializer(serializers.Serializer): id = serializers.IntegerField() title = serializers.CharField()
class RoleView(APIView): def get(self, request, *args, **kwargs): # 多条数据 # 将序列化后的数据都存到ser.data(OrderDict有序字典中)中 # roles = Role.objects.all() # ser_roles = RoleSerializer(instance=roles, many=True) # print(ser_roles, type(ser_roles)) # ListSerializer对象 # ret_roles = json.dumps(ser_roles.data, ensure_ascii=False) # 多条数据 # return HttpResponse(ret_roles) # 单条数据 role = Role.objects.all().first() ser_role = RoleSerializer(instance=role, many=False) # RoleSerializer对象 print(ser_role, type(ser_role)) # 单条数据 ret_roles = json.dumps(ser_role.data, ensure_ascii=False) return HttpResponse(ret_roles)
总结:上面能够实现数据的简单序列化,可是没法自定义字段,也没法对数据进行处理,不方便,限制较大django
from django.conf.urls import url from .views import UserInfo urlpatterns = [ url(r'^userinfo/$', UserInfo.as_view()), ]
class UserInfoView(APIView): def get(self, request, *args, **kwargs): users = UserInfo.objects.all() users_ser = UserSerializer(instance=users, many=True) users_ret = json.dumps(users_ser.data, ensure_ascii=False) # print(users_ser.data, type(users_ser.data), type(users_ser.data[0])) return HttpResponse(users_ret)
class UserSerializer(serializers.Serializer): type = serializers.IntegerField(source='user_type') user_type = serializers.CharField(source='get_user_type_display') # choices字段显示 username = serializers.CharField() pwd = serializers.CharField(source='password') # 自定义serializer中的key值 group_title = serializers.CharField(source='group.title') # 关联对象属性 roles = serializers.CharField(source='roles.all') # 多对多关系 roles_info = serializers.SerializerMethodField() # 表示自定义方法,显示querytset对象详情 def get_roles_info(self, row): roles = row.roles.all() ret = [] for item in roles: ret.append( { 'id': item.id, 'title': item.title } ) return ret
注:json
Filed
中没有定义source
参数的时候,就自动与数据库modles
定义的字段进行匹配,如上面的userrname
字段。在定义字段后,Serializer
类中能够自定义属性如typemodels
中是以choice
定义时:须要定义source
参数定义get_字段名_display
才能获取数据,这与在模板语言中的用法同样,如上面的user_type
group.title
QuerySet
对象roles_info
获取全部的role
对象的属性,处理数据能够定义方法,方法名格式为get_属性
,并return
值最终返回值执行结果:api
另:自定义字段也能够采起继承的方式,如:restful
class UsernameField(serializers.CharField): def to_representation(self, value): return 'username' + value
重写to_representation
方法,value
为从数据库取出的值,而后对value
进行处理,在返回便可
并将序列化类中的username改成
username = UsernameField()
app
class UserSerializer(serializers.ModelSerializer): user_type = serializers.CharField(source='get_user_type_display') roles = serializers.CharField(source='roles.all') # 外键关联 roles_info = serializers.SerializerMethodField() # 表示自定义方法,显示外键关联详情 group_title = serializers.CharField(source='group.title') def get_roles_info(self, row): roles = row.roles.all() ret = [] for item in roles: ret.append( { 'id': item.id, 'title': item.title } ) return ret class Meta: model = UserInfo # fields = '__all__' # 为所有的字段作匹配 fields = ['user_type', 'username', 'password', 'group', 'group_title', 'roles', 'roles_info'] # 自定义须要展现的字段 extra_kwargs = {'group': {'source': 'group_id'}}
ModelSerializer
与Serializer
区别在于:ModelSerializer
支持了Serializer
中全部的操做,而且经过自动生成全部数据字段与序列化类的一一对应关系,而不用本身手动添加。
即Serializer
是ModelSerializer
的父类,因此ModelSerializer
才会支持Serializer
的全部操做
返回结果
在上面,看到在进行连表查询的时候,只能获取到外键关联对象,在当前表中存储的id,怎样拿到外键关联对象的具体信息。
class UserSerializer(serializers.ModelSerializer): # 自动向内部进行深度查询 depth表示查询层数 class Meta: model = UserInfo # fields = "__all__" fields = ['id','username','password','group','roles'] depth = 1 # 0 ~ 10 默认的depth为0 class UserInfoView(APIView): def get(self, request, *args, **kwargs): users = UserInfo.objects.all() users_ser = UserSerializer(instance=users, many=True) users_ret = json.dumps(users_ser.data, ensure_ascii=False) # print(users_ser.data, type(users_ser.data), type(users_ser.data[0])) return HttpResponse(users_ret)
注:这里的depth就表示深度查询的层数,默认的层数为0,层数越多查询效率越慢。
返回结果
在上面咱们看到,在返回组group的时候是返回该组的id
,或者用depth
深度控制,返回组的详细信息。在restful规范中,规定应该给出相应的详情连接,能够经过url拼接,在django rest framework中也有相对应的实现。
首先改写一下用户信息序列化类,使之可以提供用户组详情的有关url
class UserSerializer(serializers.ModelSerializer): group = serializers.HyperlinkedIdentityField(view_name='api:gp', lookup_field='group_id', lookup_url_kwarg='xxx') # view_name参数 进行传参的时候是参考路由匹配中的name与namespace参数 # lookeup_field参数是根据在UserInfo表中的连表查询字段group_id # look_url_kwarg参数在作url反向解析的时候会用到 class Meta: model = UserInfo fields = ['id','username','password','group','roles'] depth = 1 # 0 ~ 10 class UserInfoView(APIView): def get(self, request, *args, **kwargs): users = UserInfo.objects.all() users_ser = UserSerializer(instance=users, many=True, context={'request': request}) # 在作连接的时候须要添加context参数 users_ret = json.dumps(users_ser.data, ensure_ascii=False) # print(users_ser.data, type(users_ser.data), type(users_ser.data[0])) return HttpResponse(users_ret) # 添加group序列化类 class GroupSerializer(serializers.ModelSerializer): class Meta: model = UserGroup fields = "__all__" # 返回用户组的详细信息 class GroupView(APIView): def get(self,request,*args,**kwargs): pk = kwargs.get('xxx') obj = UserGroup.objects.filter(pk=pk).first() ser = GroupSerializer(instance=obj,many=False) ret = json.dumps(ser.data,ensure_ascii=False) return HttpResponse(ret)
返回结果
当咱们点解用户组详情连接后,返回结果
序列化不只能够作数据的返回,也能够对前端提交的数据进行校验。
class TitleValidator(object): def __init__(self, base): self.base = base def __call__(self, value): if not value.startswith(self.base): message = '标题必须以 %s 为开头。' % self.base raise serializers.ValidationError(message) def set_context(self, serializer_field): # 执行验证以前调用,serializer_fields是当前字段对象 pass class UserGroupSerializer(serializers.Serializer): title = serializers.CharField(error_messages={'required': '标题不能为空'}, validators=[TitleValidator('Django'),]) class UserGroupView(APIView): def post(self,request,*args,**kwargs): print(request.data) ser = UserGroupSerializer(data=request.data) if ser.is_valid(): print(ser.validated_data['title']) else: print(ser.errors) return HttpResponse('提交数据')
上面的TitileValidator
类封装了对request.data
前端传来的数据的校验,title
相对应的是数据中的key
为title
的值。TitileValidator
实现了call()
特殊方法,并把具体的验证逻辑封装到里边,是一个可直接调用的对象。而self.base
则为具体的title
对应的数据,进行处理。
class UserGroupSerializer(serializers.Serializer): title = serializers.CharField() def validate_title(self, value): from rest_framework import exceptions if not value: raise exceptions.ValidationError('不可为空') return value class UserGroupView(APIView): def post(self,request,*args,**kwargs): print(request.data) ser = UserGroupSerializer(data=request.data) if ser.is_valid(): print(ser.validated_data['title']) else: print(ser.errors) return HttpResponse('提交数据')
在定义钩子方法的时候,钩子函数是以validate_字段名
的方式进行命名的。只有遵循这样的格式,在Serializer
内部会对钩子函数的名字进行拆分并识别出来。在validate_title
内部封装了对数据的校验操做,value
则为具体的值