先創建數據庫,並添加相應的數據,用來後面序列化使用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
則爲具體的值