1. 序列化基本使用
數據準備:
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)
name = models.CharField(max_length=32, unique=True)
pwd = models.CharField(max_length=64)
user_group = models.ForeignKey('UserGroup', on_delete=models.CASCADE)
role = models.ManyToManyField('Role')
class Token(models.Model):
user_info = models.OneToOneField(to='UserInfo', on_delete=models.CASCADE)
token = models.CharField(max_length=64)
class UserGroup(models.Model):
title = models.CharField(max_length=32)
class Role(models.Model):
title = models.CharField(max_length=32)
生成的數據表:
在角色表中添加如下數據:
原先使用 json.dumps
方法對從數據庫中獲取到的數據進行序列化:
urls.py:
from django.urls import path, re_path
from . import views
urlpatterns = [
re_path('(?P<version>[v1,v2]+)/roles/', views.RolesView.as_view()),
]
views.py:
from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from . import models
import json
class RolesView(APIView):
def get(self, request, *args, **kwargs):
roles = models.Role.objects.all()
print(roles) # <QuerySet [<Role: Role object (1)>, <Role: Role object (2)>]>
roles = models.Role.objects.all().values('id', 'title')
print(roles) # <QuerySet [{'id': 1, 'title': '管理員'}, {'id': 2, 'title': '超級管理員'}]>
roles = list(roles) # [<Role: Role object (1)>, <Role: Role object (2)>]
print(roles) # [{'id': 1, 'title': '管理員'}, {'id': 2, 'title': '超級管理員'}]
ret = json.dumps(roles, ensure_ascii=False)
return HttpResponse(ret)
現在我們可以使用Django REST framework中的序列化來對從數據庫中的獲取的數據進行序列化:
views.py:
from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from . import models
import json
from rest_framework import serializers
class MySerializers(serializers.Serializer):
"""
自定義序列化類
"""
id = serializers.IntegerField()
title = serializers.CharField()
class RolesView(APIView):
def get(self, request, *args, **kwargs):
roles = models.Role.objects.all()
# 因爲對象不止一個,序列化[obj,obj,obj]這種,要使用many=True
serializers = MySerializers(instance=roles, many=True)
print(serializers)
"""
MySerializers(instance=<QuerySet [<Role: Role object (1)>, <Role: Role object (2)>]>, many=True):
id = IntegerField()
title = CharField()
"""
# serializers.data是已經轉換完成的結果
print(serializers.data) # [OrderedDict([('id', 1), ('title', '管理員')]), OrderedDict([('id', 2), ('title', '超級管理員')])]
ret = json.dumps(serializers.data, ensure_ascii=False)
return HttpResponse(ret)
對於從數據庫中獲取一條數據,如果適用序列化:
views.py:
from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from . import models
import json
from rest_framework import serializers
class MySerializers(serializers.Serializer):
"""
自定義序列化類
"""
id = serializers.IntegerField()
title = serializers.CharField()
class RolesView(APIView):
def get(self, request, *args, **kwargs):
roles = models.Role.objects.first()
# 因爲就一個對象,序列化obj,要使用many=False
serializers = MySerializers(instance=roles, many=False) # 默認也是False
print(serializers)
"""
MySerializers(instance=<Role: Role object (1)>):
id = IntegerField()
title = CharField()
"""
print(serializers.data) # {'id': 1, 'title': '管理員'}
# serializers.data是已經轉換完成的結果
ret = json.dumps(serializers.data, ensure_ascii=False)
return HttpResponse(ret)
2. 自定義字段
Django REST framework的序列化可以允許我們自定義字段,從數據庫中獲取字段值也特別方便:
from django.urls import path, re_path
from . import views
urlpatterns = [
re_path('(?P<version>[v1,v2]+)/userinfo/', views.UserinfoView.as_view()),
]
from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from . import models
import json
from rest_framework import serializers
class UserinfoSerializer(serializers.Serializer):
username = serializers.CharField()
pwd = serializers.CharField()
user_type_id = serializers.CharField(source='user_type') # source對應數據庫中字段,row.user_type
user_type_title = serializers.CharField(source='get_user_type_display') # row.get_user_type_display()
group_title = serializers.CharField(source='user_group.title')
rls = serializers.SerializerMethodField() # 自定義展示
def get_rls(self, row):
row_obj_list = row.role.all()
ret = []
for item in row_obj_list:
ret.append({'id': item.id, 'title': item.title})
return ret
class UserinfoView(APIView):
def get(self, request, *args, **kwargs):
userinfo = models.UserInfo.objects.all()
userinfo_serializer = UserinfoSerializer(userinfo, many=True)
ret = json.dumps(userinfo_serializer.data, ensure_ascii=False)
return HttpResponse(f"{ret}")
3. ModelSerializer
ModelSerializer類繼承了Serializer,內部做了一些操作可以自動生成所有的字段:
class UserinfoSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
class UserinfoView(APIView):
def get(self, request, *args, **kwargs):
userinfo = models.UserInfo.objects.all()
userinfo_serializer = UserinfoSerializer(userinfo, many=True)
ret = json.dumps(userinfo_serializer.data, ensure_ascii=False)
return HttpResponse(f"{ret}")
簡單的可以直接用數據庫的字段適用ModelSerializer生成,複雜的可以自定義:
class UserinfoSerializer(serializers.ModelSerializer):
user_type_title = serializers.CharField(source='get_user_type_display')
group_title = serializers.CharField(source='user_group.title')
rls = serializers.SerializerMethodField()
class Meta:
model = models.UserInfo
# fields = "__all__"
fields = ['id', 'username', 'pwd', 'rls', 'user_type_title', 'group_title',]
def get_rls(self, row):
row_obj_list = row.role.all()
ret = []
for item in row_obj_list:
ret.append({'id': item.id, 'title': item.title})
return ret
class UserinfoView(APIView):
def get(self, request, *args, **kwargs):
userinfo = models.UserInfo.objects.all()
userinfo_serializer = UserinfoSerializer(userinfo, many=True)
ret = json.dumps(userinfo_serializer.data, ensure_ascii=False)
return HttpResponse(f"{ret}")
生成字段的時候可以額外加一些參數,可以不用再定義group_title:
class UserinfoSerializer(serializers.ModelSerializer):
user_type_title = serializers.CharField(source='get_user_type_display')
# group_title = serializers.CharField(source='user_group.title')
rls = serializers.SerializerMethodField()
class Meta:
model = models.UserInfo
# fields = "__all__"
fields = ['id', 'username', 'pwd', 'rls', 'user_type_title', ]
extra_kwargs = {'group_title': {'source': 'user_group.title'}} # 和上面自定義一樣
def get_rls(self, row):
row_obj_list = row.role.all()
ret = []
for item in row_obj_list:
ret.append({'id': item.id, 'title': item.title})
return ret
class UserinfoView(APIView):
def get(self, request, *args, **kwargs):
userinfo = models.UserInfo.objects.all()
userinfo_serializer = UserinfoSerializer(userinfo, many=True)
ret = json.dumps(userinfo_serializer.data, ensure_ascii=False)
return HttpResponse(f"{ret}")
4. 深度控制
只需要在Meta中設置 depth
字段就可以 自動序列化連表 獲取關聯表中的字段:
class UserinfoSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
"""
depth:0~10,0表示只獲取UserInfo中的表中的字段的值
"""
depth = 1
class UserinfoView(APIView):
def get(self, request, *args, **kwargs):
userinfo = models.UserInfo.objects.all()
userinfo_serializer = UserinfoSerializer(userinfo, many=True)
ret = json.dumps(userinfo_serializer.data, ensure_ascii=False)
return HttpResponse(f"{ret}")
class UserinfoSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = ['id', 'username', 'pwd', 'user_type', 'user_group', 'role']
depth = 1
5. 生成鏈接
Django REST framework中的序列化也可以幫助我們生成超鏈接:
urls.py:
from django.urls import path, re_path
from . import views
urlpatterns = [
re_path('(?P<version>[v1,v2]+)/userinfo/', views.UserinfoView.as_view()),
re_path('(?P<version>[v1,v2]+)/group/(?P<pk>\d+)', views.GroupView.as_view(), name='gp'),
]
from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from . import models
import json
from rest_framework import serializers
class UserinfoSerializer(serializers.ModelSerializer):
group = serializers.HyperlinkedIdentityField(view_name='gp', lookup_url_kwarg='pk',
lookup_field='user_group_id') # pk和url上自定義的pk有關係
class Meta:
model = models.UserInfo
fields = ['id', 'username', 'pwd', 'user_type', 'user_group', 'role', 'group']
depth = 1
class UserinfoView(APIView):
def get(self, request, *args, **kwargs):
userinfo = models.UserInfo.objects.all()
userinfo_serializer = UserinfoSerializer(userinfo, many=True, context={'request': request})
ret = json.dumps(userinfo_serializer.data, ensure_ascii=False)
return HttpResponse(f"{ret}")
class GroupSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserGroup
fields = '__all__'
class GroupView(APIView):
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk') # url傳過來的pk對應/(?P<version>[v1,v2]+)/group/(?P<pk>\d+)/
obj = models.UserGroup.objects.filter(pk=pk).first()
group_serializer = GroupSerializer(instance=obj, many=False)
ret = json.dumps(group_serializer.data, ensure_ascii=False)
return HttpResponse(f"{ret}")
6. 請求數據校驗
Django REST framework序列化還可以做 請求數據校驗
,簡單的數據校驗:
class UserGroupSerializer(serializers.Serializer):
# title = serializers.CharField(error_messages={'required':'dsdsd'})#error_messages暫時沒作用
# 寫需要校驗的字段
title = serializers.CharField()
class UserGroupView(APIView):
def post(self, request, *args, **kwargs):
print(request.data) # {'title': ''}
ser = UserGroupSerializer(data=request.data)
if not ser.is_valid():
print(
ser.errors['title'][0]) # {'title': [ErrorDetail(string='This field may not be blank.', code='blank')]}
else:
print(ser.validated_data,
type(ser.validated_data)) # OrderedDict([('title', '3組')]) <class 'collections.OrderedDict'>
print(ser.validated_data['title']) # 3組
return HttpResponse()
7. 自定義驗證規則
簡單的數據校驗一般不能滿足需求,很多情況下需要自定義驗證規則校驗數據:
class UserGroupValidator:
def __init__(self, base):
self.base = str(base)
def __call__(self, value):
"""數據一提交過來就會執行這個__call__方法"""
print('提交過來title的值', value) # value是提交過來的值
if not value.endswith(self.base):
message = '標題必須以%s結尾!' % self.base
raise serializers.ValidationError(message)
def set_context(self, serializer_field):
"""執行驗證之前調用,serializer_field是當前字段對象,這裏用不到"""
pass
class UserGroupSerializer(serializers.Serializer):
title = serializers.CharField(validators=[UserGroupValidator('組'), ])
class UserGroupView(APIView):
def post(self, request, *args, **kwargs):
# print(request.data) # {'title': '3'}
ser = UserGroupSerializer(data=request.data)
if not ser.is_valid():
print(
ser.errors['title'][0]) # {'title': [ErrorDetail(string='This field may not be blank.', code='blank')]}
else:
print(ser.validated_data,
type(ser.validated_data)) # OrderedDict([('title', '3組')]) <class 'collections.OrderedDict'>
print(ser.validated_data['title']) # 3組
return HttpResponse()
自定義驗證規則時,需要用到鉤子函數,需要從 is_valid
方法開始找。