09 序列化器Serializer 與模型類序列化器ModelSerializer
阿新 • • 發佈:2021-12-21
序列化器的作用 1. 序列化,序列化器會把模型物件轉換成字典,經過response以後變成json字串 2. 反序列化,把客戶端傳送過來的資料,經過request以後變成字典,序列化器可以把字典轉成模型 3. 反序列化,完成資料校驗功能
2 序列化器的序列化
2.1 基本使用
from django.db import models # Create your models here. class Book(models.Model): title = models.CharField(max_length=32,default='紅') price = models.IntegerField(default='0') # pub_date = models.DateField() # sqlite對日期的處理有問題,換成mysql publish = models.CharField(max_length=32,default='出')
2.1.2 路由urls.py
from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('books/', views.BookView.as_view()), path('books/<int:pk>', views.BookDetailView.as_view()), ]
2.1.3 檢視層views.py
from django.shortcuts import render # Create your views here. # def test(request): # request.session['name']='lqz' #### 查詢所有圖書的檢視類 from rest_framework.views import APIView from app01.models import Book # 絕對匯入 # from .models import Book # 相對匯入,用了相對匯入,當前py檔案,不能以指令碼形式執行from .serializer import BookSerializer from rest_framework.response import Response # 針對於某個表模型,總共5個介面 # 獲取所有 get # 獲取單個 get # 刪除單個 delete # 修改單個 update # 新增單個 post # 以後你寫的所有介面(跟資料庫相關),都是這個5個或這5個的變形 class BookView(APIView): def get(self, request, *args, **kwargs): # 查詢出所有圖書 books = Book.objects.all() # 把qs物件序列化成字典,使用序列化類完成序列化 # instance=None, 是要序列化的物件(可以是單個物件,可以是多個物件(放到列表或者qs物件),一定要寫many=True) # data=empty 反序列化的字典,目前還沒用到 print(books) ser = BookSerializer(instance=books, many=True) # 傳入要序列化的資料 print(ser.data) # 返回給前端 ser.data 是個字典 # 如果是瀏覽器,會有一個好看的頁面(註冊app),如果是postman,就是json格式 return Response(data=ser.data) # 新增 def post(self, request, *args, **kwargs): # 前端傳入的資料,在request.data中,是個字典 # 如果不使用序列化類,如何儲存 # book=Book(title=request.data.get('title')) # book.save() # 使用序列化類做儲存 ser = BookSerializer(data=request.data) # 資料校驗:如果是True,表示校驗通過,直接儲存 if ser.is_valid(): ser.save() # 呼叫儲存,但是有問題,儲存不了,一定要在序列化類中重寫某個方法 return Response(ser.data) # 又做了一次序列化,返回給了前端 else: return Response(ser.errors) class BookDetailView(APIView): def get(self, request, pk): # 查詢某一本圖書 books = Book.objects.all().filter(pk=pk).first() ser = BookSerializer(instance=books) # 傳入要序列化的資料 return Response(data=ser.data) def delete(self, request, pk): # 跟序列化類沒有關係 Book.objects.all().filter(pk=pk).delete() return Response() def put(self, request, pk): book = Book.objects.filter(pk=pk).first() ser = BookSerializer(instance=book, data=request.data) # 資料校驗:如果是True,表示校驗通過,直接儲存 if ser.is_valid(): ser.save() # 呼叫儲存,但是有問題,儲存不了,一定要在序列化類中重寫update方法 return Response(ser.data) # 又做了一次序列化,返回給了前端
# 寫序列化類 from rest_framework import serializers from .models import Book from rest_framework.exceptions import ValidationError class BookSerializer(serializers.Serializer): # 一定要繼承一個序列化的基類 # 寫欄位,你想序列化哪個欄位,就寫哪個 title = serializers.CharField(max_length=8, min_length=3) price = serializers.IntegerField() # pub_date = serializers.DateField() publish = serializers.CharField() # 重寫create,使它能夠支援新增儲存 (派生) def create(self, validated_data): # validated_data校驗過後的資料 book = Book.objects.create(**validated_data) return book # 一定不要忘了return 物件,否則在檢視類中用ser.data 就報錯了 # 重寫 update 支援修改 def update(self, instance, validated_data): instance.title = validated_data.get('title') instance.price = validated_data.get('price') instance.publish = validated_data.get('publish') instance.save() return instance # validate_欄位名 先走欄位自己的,再走區域性鉤子 def validate_title(self, item): print(item) # 校驗欄位,不能以sb開頭 if item.startswith('sb'): raise ValidationError('不能以sb開頭') return item # 全域性鉤子 def validate(self, attrs): # 校驗失敗,拋異常 if attrs.get('title') == attrs.get('publish'): raise ValidationError('標題和出版社不能一樣') return attrs
2.2 常用欄位
注意:serializer不是隻能為資料庫模型類定義,也可以為非資料庫模型類的資料定義。serializer是獨立於資料庫之外的存在。
常用欄位型別:
2.3 常用欄位引數
選項引數:
通用引數:
3 序列化器的反序列化
3.1 基本使用(需要重寫create,update,見上面)
#新增
def post(self, request, *args, **kwargs): # 前端傳入的資料,在request.data中,是個字典 # 如果不使用序列化類,如何儲存 # book=Book(title=request.data.get('title')) # book.save() # 使用序列化類做儲存 ser = BookSerializer(data=request.data) # 資料校驗:如果是True,表示校驗通過,直接儲存 if ser.is_valid(): ser.save() # 呼叫儲存,但是有問題,儲存不了,一定要在序列化類中重寫某個方法 return Response(ser.data) # 又做了一次序列化,返回給了前端 else: return Response(ser.errors)
#修改
def put(self, request, pk): book = Book.objects.filter(pk=pk).first() ser = BookSerializer(instance=book, data=request.data) # 資料校驗:如果是True,表示校驗通過,直接儲存 if ser.is_valid(): ser.save() # 呼叫儲存,但是有問題,儲存不了,一定要在序列化類中重寫update方法 return Response(ser.data) # 又做了一次序列化,返回給了前端
3.2 資料校驗
# 欄位自己校驗規則 title = serializers.CharField(max_length=8, min_length=3) # 區域性鉤子 # validate_欄位名 先走欄位自己的,再走區域性鉤子 def validate_title(self, item): print(item) # 校驗欄位,不能以sb開頭 if item.startswith('sb'): raise ValidationError('不能以sb開頭') return item # 全域性鉤子 def validate(self, attrs): # 校驗失敗,拋異常 if attrs.get('title') == attrs.get('publish'): raise ValidationError('標題和出版社不能一樣') return attrs
4 模型類序列化器ModelSerializer
反序列化,正常情況不需要重寫 create和update 序列化:跟表模型有對應關係,不需要一個個欄位都寫了
# class BookModelSerializer(serializers.ModelSerializer): # # 跟某個表模型建立關係 # class Meta: # model = Book # 跟哪個表建立關係 # fields = ['title','price','id','publish'] # 要序列化哪些欄位 # # fields = '__all__' # 所有欄位都序列化 # # # # 瞭解 # # exclude=['title'] # 除了某個欄位外 # # depth=1 # 表關聯 # # # # #重點 # # # read_only 只讀,只序列化 # # # write_only # # # 重寫某個欄位 # title=serializers.CharField(max_length=8,min_length=3) # # # 區域性和全域性鉤子跟之前一模一樣 # # def validate_price(self, price): # if not price>100: # raise ValidationError('價格必須大於100') # # return price class BookModelSerializer(serializers.ModelSerializer): # 跟某個表模型建立關係 class Meta: model = Book # 跟哪個表建立關係 fields = ['title', 'price', 'id', 'publish'] # 要序列化哪些欄位 # 重點 # 額外給某些欄位傳引數 # extra_kwargs = { # 'title': {'max_length': 8, 'min_length': 3}, # 'price': {'min_value': 100} # } # read_only 只讀,只序列化 # write_only 只寫,只做反序列化,這個欄位不做序列化 extra_kwargs = { 'title': {'read_only': True}, # 'price': {'write_only': True} }