rest framework 之序列化
Posted midworld
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了rest framework 之序列化相关的知识,希望对你有一定的参考价值。
一、示例
restful work 的序列号就类似于 Django 的 Form 表单。
1、api/urls.py
from django.urls import path, re_path
from api.views import UserView, ParserView, RolesView
urlpatterns = [
# path('users/', UserView.as_view()),
re_path('(?P<version>[v1|v2]+)/users/', UserView.as_view(), name='api_user'), # 解析
re_path('(?P<version>[v1|v2]+)/roles', RolesView.as_view()), # 序列化
path('parser/', ParserView.as_view(), name='api_parer'),
]
api/views.py
from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
from rest_framework import serializers
from app import models
import json
class RolesSerializers(serializers.Serializer):
"""序列化类(对应 Role 模型类中字段)"""
id = serializers.IntegerField()
name = serializers.CharField()
class RolesView(APIView):
def get(self, request, *args, **kwargs):
# 取出全部
# roles = models.Role.objects.all()
# # 序列化,两个参数,instance:接受Queryset(或者对象) mangy=True表示处理多个对象,mant=False表示处理单个对象
# ser = RolesSerializers(instance=roles, many=True)
# # 转成json格式,ensure_ascii=False表示显示中文,默认为True
# ret = json.dumps(ser.data, ensure_ascii=False)
# 取出第一个
role = models.Role.objects.all().first()
ser = RolesSerializers(instance=role, many=False)
ret = json.dumps(ser.data, ensure_ascii=False)
return HttpResponse(ret)
app/models.py
from django.db import models
class UserInfo(models.Model):
USER_TYPE = (
(1, '普通用户'),
(2, 'VIP'),
(3, 'SVIP')
)
user_type = models.IntegerField(choices=USER_TYPE)
username = models.CharField(max_length=32)
password = models.CharField(max_length=64)
group = models.ForeignKey('UserGroup', on_delete=models.CASCADE, verbose_name='所属组', null=True, blank=True)
roles = models.ManyToManyField('Role', verbose_name='角色')
class UserToken(models.Model):
user = models.OneToOneField(UserInfo, on_delete=models.CASCADE)
token = models.CharField(max_length=64)
class UserGroup(models.Model):
"""分组"""
name = models.CharField(verbose_name='组名', max_length=64)
class Role(models.Model):
"""角色"""
name = models.CharField(max_length=64, verbose_name='角色名')
- 访问:
http://127.0.0.1:8000/api/v1/roles
"id": 1, "name": "老板"
二、进阶
前面我们只序列化了没有关联的字段,对于多选字段、外键以及多对多字段都没有演示,在这里我们还将学习如何自定义一个序列化方法。
1、各个数据表数据:
2、api/urls.py
from django.urls import path, re_path
from api.views import UserView, ParserView, RolesView, UserInfoView
urlpatterns = [
# path('users/', UserView.as_view()),
re_path('(?P<version>[v1|v2]+)/users/', UserView.as_view(), name='api_user'),
re_path('(?P<version>[v1|v2]+)/roles', RolesView.as_view()), # 序列化
re_path('(?P<version>[v1|v2]+)/info', UserInfoView.as_view()), # 序列化
path('parser/', ParserView.as_view(), name='api_parer'),
]
3、api/views.py
class UserInfoSerializers(serializers.Serializer):
# 多选字段:user_type是choices(1,2,3),显示全称的方法用 get_字段名_display
type = serializers.CharField(source='get_user_type_display')
username = serializers.CharField()
password = serializers.CharField()
# 外键字段: group.name:组的名字
group = serializers.CharField(source="group.name")
# SerializerMethodField(),表示自定义显示
# 然后写一个自定义的方法
rls = serializers.SerializerMethodField()
def get_rls(self, row):
"""获取用户所有角色,get_rls 和上面自定义方法名字一致"""
print(row) # UserInfo object (2)
role_obj_list = row.roles.all()
print(role_obj_list) # <QuerySet [<Role: Role object (1)>]>
ret = []
# 获取角色的id和名字
# 以字典的键值对方式显示
for item in role_obj_list:
ret.append("id": item.id, "name": item.name)
return ret
class UserInfoView(APIView):
def get(self, request, *args, **kwargs):
users = models.UserInfo.objects.all()
ser = UserInfoSerializers(instance=users, many=True)
ret = json.dumps(ser.data, ensure_ascii=False)
return HttpResponse(ret)
- 访问:
http://127.0.0.1:8000/api/v1/info
:
["type": "普通用户", "username": "rose", "password": "123", "group": "一组", "rls": ["id": 1, "name": "老板"], "type": "VIP", "username": "john", "password": "123", "group": "二组", "rls": [], "type": "SVIP", "username": "hj", "password": "123", "group": "三组", "rls": ["id": 4, "name": "普通员工"]]
总结
- 多选字段:使用
get_字段名_display
获取字段原始值 - 外键字段:
source="外键名.要获取的字段名"
- 多对多字段:可通过自定义分实现
- 自定义方法:
mth = serializers.SerializerMethodField()
,方法名:get_mth()
三、ModelSerializer
ModelSerializer
效果类似于 Django Form 中的 ModelForm
,
class UserInfoSerializers(serializers.ModelSerializer):
type = serializers.CharField
group = serializers.CharField(source="group.name")
rls = serializers.SerializerMethodField()
def get_rls(self, row):
pass
class Meta:
model = models.UserInfo
# fields = '__all__'
fields = ['id','username','password','type','group','rls']
四、depth 控制连表的深度
当表与表之间多个相连,如果只想显示前面几层,可以使用 depth
控制连表的深度:
class UserInfoSerializers(serializers.ModelSerializer):
type = serializers.CharField
group = serializers.CharField(source="group.name")
rls = serializers.SerializerMethodField()
def get_rls(self, row):
pass
class Meta:
model = models.UserInfo
# fields = '__all__'
fields = ['id','username','password','type','group','rls']
depth = 1 # 控制为 1 层
六、HyperlinkedidentityField 生成 url
序列化关联数据表的相应字段的 url,就像下面这种:
[
"id": 1,
"publish": "http://127.0.0.1:8080/api/publish/1",
"name": "红楼梦",
"price": "123.00",
"publish_date": null
,
"id": 2,
"publish": "http://127.0.0.1:8080/api/publish/2",
"name": "西游记",
"price": "234.00",
"publish_date": null
]
1、api/serializers.py
from rest_framework import serializers
from app import models
class UserInfoSerializers(serializers.ModelSerializer):
"""用户个人信息序列化"""
group = serializers.HyperlinkedIdentityField(view_name='gob', lookup_field='group_id', lookup_url_kwarg='pk')
class Meta:
model = models.UserInfo
fields = '__all__'
class RolesSerializers(serializers.Serializer):
"""序列化类"""
id = serializers.IntegerField()
name = serializers.CharField()
class GroupSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserGroup
fields = "__all__"
参数:
- view_name:关联路由 URL 中的 name 参数值,用来反向解析 URL
- lookup_field:要查找的目标字段,如:
group_id
是UserInfo
模型中的外键字段(即我们要查找的字段) - lookup_url_kwarg:关键字参数的名称,该参数对应于查找字段,一般为 pk
2、api/urls.py
from django.urls import path, re_path
from api.views import UserView, ParserView, RolesView, UserInfoView, GroupView
urlpatterns = [
re_path('(?P<version>[v1|v2]+)/info/', UserInfoView.as_view()), # 序列化
re_path('(?P<version>[v1|v2]+)/group/(?P<pk>\d+)/', GroupView.as_view(), name='gob'), # 序列化生成url
]
3、api/views.py
from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
from rest_framework.parsers import JSONParser, FormParser
from .serializers import GroupSerializer, RolesSerializers, UserInfoSerializers
from app import models
from django.http import JsonResponse
class UserInfoView(APIView):
def get(self, request, *args, **kwargs):
users = models.UserInfo.objects.all()
# 这里必须指定 context,将 request 传递给 UserInfoSerializers
user_ser = UserInfoSerializers(instance=users, many=True, context='request': request)
return JsonResponse(user_ser.data, safe=False)
class GroupView(APIView):
def get(self, request, *args, **kwargs):
# pk = kwargs.get('pk')
# group = models.UserGroup.objects.filter(pk=pk).first()
#
# group_ser = GroupSerializer(instance=group, many=False)
# # ret = json.dumps(ser.data, ensure_ascii=False)
# return JsonResponse(group_ser.data, safe=False)
return HttpResponse('ok')
4、访问:http://127.0.0.1:8000/api/v2/info/
[
"id": 1,
'username': 'rose', john/hj
'password': '123',
"group": "http://127.0.0.1:8080/api/group/1",
"roles": [
2,
]
,
"id": 2,
'username': 'john',
'password': '123',
"group": "http://127.0.0.1:8080/api/group/2",
"roles": [
1,
]
,
]
七、用户请求数据验证
验证用户请求的数据是否合法
1、api/serializers.py
from rest_framework import serializers
class UserGroupSerializers(serializers.Serializer):
"""用户请求验证"""
title = serializers.CharField()
2、api/views.py
from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
from .serializers import GroupSerializer, RolesSerializers, UserInfoSerializers, UserGroupSerializers
class UserGroupView(APIView):
"""用户请求验证"""
def post(self, request, *args, **kwargs):
usergroup_ser = UserGroupSerializers(data=request.data)
if usergroup_ser.is_valid():
print(usergroup_ser.validated_data['title'])
else:
print(usergroup_ser.errors)
return HttpResponse('用户提交数据错误')
3、利用 postman 模拟用户请求发送数据
请求方式 post,参数格式 JSON:
当请求的数据为空时,会自动验证数据的合法性:
八、自定义验证规则
你可以自定义验证规则,比如验证用户输入的字段必须以什么开头,必须是邮箱格式等:
1、api/serializers.py
class GroupValidation:
"""自定义验证规则"""
def __init__(self, base):
self.base = base # love
def __call__(self, value, *args, **kwargs):
if not value.startswith(self.base):
msg = '标题必须以 %s 开头' % self.base
raise serializers.ValidationError(msg)
class UserGroupSerializers(serializers.Serializer):
"""用户请求数据验证"""
# title = serializers.CharField()
title = serializers.CharField(validators=[GroupValidation('love'), ])
2、其余的不变,现在验证规则按照我们设置的走,错误提示也一样:
以上是关于rest framework 之序列化的主要内容,如果未能解决你的问题,请参考以下文章
Django REST framework之序列化组件以及源码分析+全局局部Hook
Django REST framework框架之GET, POST, PUT, PATCH, DELETE等API请求接口设计