#做用: 1. 序列化,序列化器會把模型對象轉換成字典,通過response之後變成json字符串 -Book模型--序列化器--->字典--經過drf:Response--》json格式字符串--->傳給前端 2. 反序列化,把客戶端發送過來的數據,通過request之後變成字典,序列化器能夠把字典轉成模型 json格式數據---經過drf:Request-->字典---序列化器---》Book模型 3. 反序列化,完成數據校驗功能
# 序列化的使用 -寫一個序列化類繼承serializers.Serializer -在類中寫要序列化的字段 -在視圖類中,實例化獲得一個序列化類的對象,把要序列化的數據傳入 ser=BookSerializer(instance=res,many=True) -獲得字典 ser.data就是序列化後的字典
'''
5個接口 1. 查詢全部 Book--》get 2. 查詢單個 BookDetali--》get 3. 新增一個 Book--》post 4. 刪除一個 BookDetali--》delete 5. 修改一個 BookDetali--》put '''
url:127.0.0.1.8000/books/ # 注意最後面的 /必定要寫
models.py # 創建好模型,進行數據遷移,在數據庫中手動添加至少2條數據前端
from django.db import models class Book(models.Model): id = models.AutoField(primary_key=True) title = models.CharField(max_length=32,null=True) #測試read_only price = models.DecimalField(max_digits=5, decimal_places=2) publish = models.CharField(max_length=32)
urls.py #配置好路由python
path('books/', views.Book.as_view()),
views.py #寫視圖類git
from rest_framework.views import APIView from rest_framework.response import Response from app01 import models from app01.serializer import BookSerializer class Book(APIView): def get(self, request, *args, **kwargs): res = models.Book.objects.all() # 藉助序列化器 # 若是是多條,就是many=True # 若是是單個對象,就不寫 ser = BookSerializer(instance=res, many=True) print(type(ser)) # rest_framework.serializers.ListSerializer # 經過序列化器獲得的字典 # ser.data print(ser.data) return Response(ser.data)
serializer.py #在app中建立存放序列化器的 類的文件 serializer.py 並寫BookSerializer類數據庫
# 序列化器類(序列化Book表) # from rest_framework.serializers import Serializer from rest_framework import serializers from rest_framework.exceptions import ValidationError from app01 import models class BookSerializer(serializers.Serializer): # 要序列化哪一個字段 id = serializers.IntegerField(required=False) # id=serializers.CharField() title = serializers.CharField(max_length=32,min_length=2,read_only=True) price = serializers.DecimalField(max_digits=5, decimal_places=2) # 序列化的時候看不到,由於write_only=True
publish = serializers.CharField(max_length=32,write_only=True)
url:127.0.0.1.8000/books/1 #後面的數字表明查詢id爲幾的數據
urls.py中加django
re_path('^books/(?P<id>\d+)', views.BookDetail.as_view()),
views.py中加json
class BookDetail(APIView): def get(self, request, id): res = models.Book.objects.all().filter(id=id).first() # 單個,去掉many=True # 加many=True和不加,ser不是同一個對象,查單個是BookSerializer對象,查多個是ListSerializer對象,這是由源碼中元類決定的 ser = BookSerializer(instance=res) print(type(ser)) # 打印出 app01.serializer.BookSerializer return Response(ser.data)
ps:新增必須寫create方法app
urls.py 不變源碼分析
views.pypost
class Book(APIView): def get(self, request, *args, **kwargs): ... def post(self, request): # post提交的數據都在request.data 是個字典 print(request.data) ser = BookSerializer(data=request.data) if ser.is_valid(): # 校驗數據是否合法 ser.save() # 保存到數據庫中 return Response(ser.data) else: # 沒有校驗經過的錯誤信息 return Response(ser.errors)
serializer.py
# 若是序列化類繼承的是Serializer,必須重寫create方法 class BookSerializer(serializers.Serializer): ... def create(self, validated_data): # 爲何要重寫create?爲了跟views.py裏面的Book表創建關係 res=models.Book.objects.create(**validated_data) print(res) return res
ps:必須寫update方法測試
urls.py不變
views.py
class BookDetail(APIView): def get(self, request, id): ... def put(self, request, id): # 經過id取到對象 res = {'code': 100, 'msg': ''} try: book = models.Book.objects.get(id=id) ser = BookSerializer(instance=book, data=request.data) ser.is_valid(raise_exception=True) ser.save() res['msg'] = '修改爲功' res['result'] = ser.data except Exception as e: res['code'] = 101 res['msg'] = str(e) return Response(res)
serializer.py
class BookSerializer(serializers.Serializer): ... def update(self, book, validated_data): book.title=validated_data.get('title') book.price=validated_data.get('price') book.publish=validated_data.get('publish') book.save() return book
views.py
class BookDetail(APIView): ... def delete(self,request,id): response = {'code': 100, 'msg': '刪除成功'} models.Book.objects.filter(id=id).delete() return Response(response)
# 經常使用字段類型 -IntegerField -CharField -DecimalField -DateTimeField -。。。跟models中大差不差 # 經常使用字段參數 -選項參數 max_length 最大長度 min_lenght 最小長度 allow_blank 是否容許爲空 trim_whitespace 是否截斷空白字符 max_value 最小值 min_value 最大值 -通用參數 #重點 read_only 代表該字段僅用於序列化輸出,默認False write_only 代表該字段僅用於反序列化輸入,默認False # 掌握 required 代表該字段在反序列化時必須輸入,默認True default 反序列化時使用的默認值 allow_null 代表該字段是否容許傳入None,默認False # 瞭解 validators 該字段使用的驗證器 error_messages 包含錯誤編號與錯誤信息的字典
同三中3.增長一個 裏面的保存
validators校驗,局部鉤子,全局鉤子
ps:validators 列表裏面能夠傳多個值進行校驗
# 三種方式 -字段本身的校驗規則(max_length...) -validators的校驗 publish = serializers.CharField(max_length=32,validators=[check,]) def check(data): if len(data)>10: raise ValidationError('最長不能超過10') else: return data -局部和全局鉤子 # 局部鉤子,validate_字段名,須要帶一個data,data就是該字段的數據 def validate_title(self, data): if data.startswith('sb'): raise ValidationError('不能以sb開頭') else: return data # 全局鉤子 def validate(self, attrs): title=attrs.get('title') publish=attrs.get('publish') if title==publish: raise ValidationError('書名不能跟出版社同名') else: return attrs
read_only 代表該字段僅用於序列化輸出,默認False write_only 代表該字段僅用於反序列化輸入,默認False class BookSerializer(serializers.Serializer): # 要序列化哪一個字段 id = serializers.IntegerField(required=False) # id=serializers.CharField() title = serializers.CharField(max_length=32,min_length=2,read_only=True) price = serializers.DecimalField(max_digits=5, decimal_places=2) # 序列化的時候看不到 publish = serializers.CharField(max_length=32,validators=[check,],write_only=True)
總結:
1用法一: 修改返回到前端的字段名 # 若source=title 那麼字段名就不能再叫title,這裏叫了name name = serializers.CharField(max_length=32,min_length=2,source='title') 2用法二: 若是表模型中有方法 class Book(models.Model): ... def test(self): # python是強類型語言,不支持字符串和數字直接相加 return self.title+str(self.price) # 執行表模型中的test方法,而且把返回值賦值給xxx xxx=serializers.CharField(source='test') 3用法三: source支持跨表操做 addr=serializers.CharField(source='publish.addr') # 能夠去看源碼,內部如何實現的
代碼:
urls.py
models.py
from django.db import models class Book(models.Model): id = models.AutoField(primary_key=True) title = models.CharField(max_length=32,null=True) #測試read_only price = models.DecimalField(max_digits=5, decimal_places=2) # publish = models.CharField(max_length=32) #修改後 publish = models.ForeignKey(to='Publish',null=True,on_delete=models.CASCADE) #這是在測試source第一種方法時加的 def test(self): # python是強類型語言,不支持字符串和數字直接相加 return self.title+str(self.price) #新建一張publish表 class Publish(models.Model): name=models.CharField(max_length=32) addr=models.CharField(max_length=32) #重寫__str__ def __str__(self): return self.name
views.py
class BookSerializer(serializers.Serializer): id = serializers.IntegerField(required=False) #方法一 name = serializers.CharField(max_length=32,min_length=2,source='title') price = serializers.DecimalField(max_digits=5, decimal_places=2) #方法三,要直接顯示出publish的名字 ,或 在models.py中重寫__str__ publish = serializers.CharField(max_length=32,source='publish.name') #方法二 xxx=serializers.CharField(source='test') #方法三:跨表 publish_addr=serializers.CharField(source='publish.addr')
1 原來用的Serilizer跟表模型沒有直接聯繫, 模型類序列化器ModelSerilizer,跟表模型有對應關係 2 使用 class BookModelSerializer(serializers.ModelSerializer): class Meta: model=表模型 # 跟哪一個表模型創建關係 fields=[字段,字段] # 序列化的字段,反序列化的字段 fields='__all__' # 全部字段都序列化,反序列化 exclude=[字段,字段] # 排除哪些字段(不能跟fields同時使用) read_only_fields=['price','publish'] # 序列化顯示的字段 write_only_fields=['title'] # 反序列化須要傳入的字段 extra_kwargs ={'title':{'max_length':32,'write_only':True}} depth=1 # 瞭解,跨表1查詢,最多建議寫3 # 重寫某些字段 publish = serializers.CharField(max_length=32,source='publish.name') # 局部鉤子,全局鉤子,跟原來徹底同樣 3 新增,修改 -通通不用重寫create和update方法了,在ModelSerializer中重寫了create和update
#方式一:Serializer class BookSerializer(serializers.Serializer): id = serializers.IntegerField(required=False) name = serializers.CharField(max_length=32,min_length=2,source='title') price = serializers.DecimalField(max_digits=5, decimal_places=2) publish = serializers.SerializerMethodField() def get_publish(self,obj): dic={'name':obj.publish.name,'addr':obj.publish.addr} return dic #方式二:ModelSerializer class BookModelSerializer(serializers.ModelSerializer): class Meta: model = models.Book fields = '__all__' publish = serializers.SerializerMethodField() def get_publish(self,obj): dic={'name':obj.publish.name,'addr':obj.publish.addr} return dic # 方式三:使用序列化類的嵌套 class PublishSerializer(serializers.ModelSerializer): class Meta: model = models.Publish # fields = '__all__' fields = ['name','addr'] class BookModelSerializer(serializers.ModelSerializer): publish = PublishSerializer() class Meta: model = models.Book fields = '__all__'
#序列化組件,先調用__new__方法,若是many=True,生成ListSerializer對象,若是爲False,生成Serializer對象 #序列化對象.data方法--調用父類data方法---調用對象本身的to_representation(自定義的序列化類無此方法,去父類找) #Aerializer類裏有to_representation方法,for循環執行attribute = field.get_attribute(instance) #再去Field類裏去找get_attribute方法,self.source_attrs就是被切分的source,而後執行get_attribute方法,source_attrs #當參數傳過去,判斷是方法就加括號執行,是屬性就把值取出來