drf3 Serializers 序列化组件
為什么要用序列化組件
做前后端分離的項目,我們前后端交互一般都選擇JSON數據格式,JSON是一個輕量級的數據交互格式。 給前端數據的時候都要轉成json格式,那就需要對從數據庫拿到的數據進行序列化。 django序列化和rest_framework序列化的對比 將后端數據庫中的信息用json的格式傳給前端數據準備
DRFDemo/urls.pyfrom django.contrib import admin from django.urls import path, includeurlpatterns = [path('admin/', admin.site.urls),path('books/', include("SerDemo.urls")),]SerDemo/urls.pyurlpatterns = [path('list', BookView.as_view()),path('retrieve/<int:id>', BookEditView.as_view()),] urls from django.db import models# Create your models here.__all__ = ["Book", "Publisher", "Author"]class Book(models.Model):title = models.CharField(max_length=32, verbose_name="圖書名稱")CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))category = models.IntegerField(choices=CHOICES, verbose_name="圖書的類別")pub_time = models.DateField(verbose_name="圖書的出版日期")publisher = models.ForeignKey(to="Publisher", on_delete=None)author = models.ManyToManyField(to="Author")def __str__(self):return self.titleclass Meta:verbose_name_plural = "01-圖書表"db_table = verbose_name_pluralclass Publisher(models.Model):title = models.CharField(max_length=32, verbose_name="出版社的名稱")def __str__(self):return self.titleclass Meta:verbose_name_plural = "02-出版社表"db_table = verbose_name_pluralclass Author(models.Model):name = models.CharField(max_length=32, verbose_name="作者的姓名")def __str__(self):return self.nameclass Meta:verbose_name_plural = "03-作者表"db_table = verbose_name_plural SerDemo/models.py for table in models.__all__:admin.site.register(getattr(models, table)) SerDemo/admin.py需要自己手動,對取出來的數據進行序列化后返回
class BookView(View):# 第一版 用.values JsonResponse實現序列化def get(self, request):book_list = Book.objects.values("id", "title", "category", "pub_time", "publisher")book_list = list(book_list)ret = []for book in book_list:# print(book)publisher_id = book["publisher"]publisher_obj = Publisher.objects.filter(id=publisher_id).first()book["publisher"] = { # 將 publisher 對應的出版社,序列化"id": publisher_id,"title": publisher_obj.title}ret.append(book)# ret = json.dumps(book_list, ensure_ascii=False) # json.dumps 不能處理日期格式數據# return HttpResponse(ret)# 使用JsonResponse 能幫我們處理return JsonResponse(ret, safe=False, json_dumps_params={"ensure_ascii": False}) # 第一版 用.values JsonResponse實現序列化?
class BookView(View):# 第二版 用django serializers實現序列化def get(self, request):book_list = Book.objects.all()ret = serializers.serialize("json", book_list, ensure_ascii=False)return HttpResponse(ret) # 第二版 用django serializers實現序列化?序列化仍舊處于表層,第二級以下的數據顯示為數字
DRF序列化
用DRF的序列化,要遵循框架的一些標準,
-- Django我們CBV繼承類是View,現在DRF我們要用APIView
-- Django中返回的時候我們用HTTPResponse,JsonResponse,render ,DRF我們用Response
安裝 pip install djangorestframework
INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','SerDemo','rest_framework', ] 注冊到項目的app里面序列化
from rest_framework import serializersclass BookSerializer(serializers.Serializer):id = serializers.IntegerField()title = serializers.CharField(max_length=32)CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))category = serializers.ChoiceField(choices=CHOICES,source="get_category_display")pub_time = serializers.DateField() 編寫序列化的類 from rest_framework.views import APIViewfrom rest_framework.response import Response from .serializers import BookSerializer # 導入序列化類 class BookView(APIView):def get(self, request):book_obj = Book.objects.first()ret = BookSerializer(book_obj)# book_list = Book.objects.all() # 拿到所有的對象# ret = BookSerializer(book_list, many=True)return Response(ret.data) 視圖函數(序列化對象)??ret = BookSerializer(book_list, many=True)??序列化多個對象時,需要設置many=True
含外鍵數據的序列化
from rest_framework import serializersclass PublisherSerializer(serializers.Serializer):id = serializers.IntegerField()title = serializers.CharField(max_length=32)class AuthorSerializer(serializers.Serializer):id = serializers.IntegerField()name = serializers.CharField(max_length=32)class BookSerializer(serializers.Serializer):id = serializers.IntegerField()title = serializers.CharField(max_length=32)CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))category = serializers.ChoiceField(choices=CHOICES, source="get_category_display")pub_time = serializers.DateField()publisher = PublisherSerializer()author = AuthorSerializer(many=True) 外鍵關系的序列化DRF反序列化
當前端給我們發post的請求的時候~前端給我們傳過來的數據~我們要進行一些校驗然后保存到數據庫 這些校驗以及保存工作,DRF的Serializer也給我們提供了一些方法了 首先~我們要寫反序列化用的一些字段~有些字段要跟序列化區分開 Serializer提供了.is_valid() 和.save()方法將前端傳過來的數據進行反序列化,然后保存到數據庫
read_only=True #序列化
write_only=True #反序列化數據 前端傳過來的數據樣式 {"title": "Alex的使用教程","w_category": 1,"pub_time": "2018-10-09","publisher_id": 1,"author_list": [1, 2] }
接受Post前端傳過來的數據,必須在serialise類定義create方法
class BookSerializer(serializers.Serializer):id = serializers.IntegerField(required=False) #不需要校驗title = serializers.CharField(max_length=32, validators=[my_validate])CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True)w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)pub_time = serializers.DateField()publisher = PublisherSerializer(read_only=True)publisher_id = serializers.IntegerField(write_only=True)author = AuthorSerializer(many=True, read_only=True)author_list = serializers.ListField(write_only=True) #反序列化字段def create(self, validated_data): # 創建數據,接受post 數據book = Book.objects.create(title=validated_data["title"], category=validated_data["w_category"],pub_time=validated_data["pub_time"], publisher_id=validated_data["publisher_id"]) # 取數據的時候應該為前端傳過來的字段數據book.author.add(*validated_data["author_list"]) #多對多return book 反序列化serializer.py定義 post 方法接受前端傳過來的數據
class BookView(APIView):def get(self, request):# book_obj = Book.objects.first()# ret = BookSerializer(book_obj)book_list = Book.objects.all()ret = BookSerializer(book_list, many=True)return Response(ret.data)def post(self, request):print(request.data)serializer = BookSerializer(data=request.data)if serializer.is_valid():serializer.save()return Response(serializer.data) #校驗成功,反回else:return Response(serializer.errors) 反序列化views.pypost數據
反回的結果
DRF的PUT請求部分驗證
單條數據操作
from django.urls import path, include from .views import BookView, BookEditViewurlpatterns = [path('list', BookView.as_view()),path('retrieve/<int:id>', BookEditView.as_view()),]BookEditView
class BookEditView(APIView):def get(self, request, id): # 獲取單條數據book_obj = Book.objects.filter(id=id).first()ret = BookSerializer(book_obj)return Response(ret.data)def put(self, request, id): # 部分修改數據book_obj = Book.objects.filter(id=id).first()serializer = BookSerializer(book_obj, data=request.data, partial=True) # partial=True # 支持部分驗證if serializer.is_valid():serializer.save()return Response(serializer.data)else:return Response(serializer.errors)def delete(self, request, id):book_obj = Book.objects.filter(id=id).first()book_obj.delete()return Response("") 單條數據操作查看單條數據,獲取id為4的數據
修改數據
前端傳過來的數據
data = {"title": "Alex的使用教程2" }對修改的數據進行序列化處理 update 方法
class BookSerializer(serializers.Serializer):id = serializers.IntegerField(required=False) #不需要校驗title = serializers.CharField(max_length=32, validators=[my_validate])CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True)w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)pub_time = serializers.DateField()publisher = PublisherSerializer(read_only=True)publisher_id = serializers.IntegerField(write_only=True)author = AuthorSerializer(many=True, read_only=True)author_list = serializers.ListField(write_only=True)def update(self, instance, validated_data): # 處理 put 更新數據instance.title = validated_data.get("title", instance.title)instance.category = validated_data.get("category", instance.category)instance.pub_time = validated_data.get("pub_time", instance.pub_time)instance.publisher_id = validated_data.get("publisher_id", instance.publisher_id)if validated_data.get("author_list"):instance.author.set(validated_data["author_list"])instance.save()return instance Serializer的update更新數據反回的結果
DRF的驗證
class BookSerializer(serializers.Serializer):id = serializers.IntegerField(required=False) # 不需要校驗title = serializers.CharField(max_length=32, validators=[my_validate])CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True)w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)pub_time = serializers.DateField()publisher = PublisherSerializer(read_only=True)publisher_id = serializers.IntegerField(write_only=True)author = AuthorSerializer(many=True, read_only=True)author_list = serializers.ListField(write_only=True)def create(self, validated_data): # 創建數據book = Book.objects.create(title=validated_data["title"], category=validated_data["w_category"],pub_time=validated_data["pub_time"], publisher_id=validated_data["publisher_id"])book.author.add(*validated_data["author_list"]) # 多對多return bookdef update(self, instance, validated_data): # 處理 put 更新數據instance.title = validated_data.get("title", instance.title)instance.category = validated_data.get("category", instance.category)instance.pub_time = validated_data.get("pub_time", instance.pub_time)instance.publisher_id = validated_data.get("publisher_id", instance.publisher_id)if validated_data.get("author_list"):instance.author.set(validated_data["author_list"])instance.save()return instance BookSerializer def validate_title(self, value): # 對傳過來的title進行校驗if "python" not in value.lower():raise serializers.ValidationError("標題必須含有python")return valuedef validate(self, attrs):? # 全局校驗if attrs["w_category"] == 1 and attrs["publisher_id"] == 1:return attrselse:raise serializers.ValidationError("分類以及標題不符合要求")自定義驗證器
當有重疊校驗器時自定義的驗證器權重更高
def my_validate(value): # 自定義驗證器,權重更高,用在需要校驗數據的地方if "敏感信息" in value.lower():raise serializers.ValidationError("不能含有敏感信息")else:return value 使用 title = serializers.CharField(max_length=32, validators=[my_validate])?all
from rest_framework import serializers from .models import Book# 外鍵序列化 class PublisherSerializer(serializers.Serializer):id = serializers.IntegerField()title = serializers.CharField(max_length=32)class AuthorSerializer(serializers.Serializer):id = serializers.IntegerField()name = serializers.CharField(max_length=32)# # # 傳過來的書籍對象數據 # book_obj = { # "title": "Alex的使用教程", # "w_category": 1, # "pub_time": "2018-10-09", # "publisher_id": 1, # "author_list": [1, 2] # } # # data = { # "title": "Alex的使用教程2" # }def my_validate(value): # 自定義驗證器,權重更高,if "敏感信息" in value.lower():raise serializers.ValidationError("不能含有敏感信息")else:return valueclass BookSerializer(serializers.Serializer):id = serializers.IntegerField(required=False) # 不需要校驗title = serializers.CharField(max_length=32, validators=[my_validate])CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True)w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)pub_time = serializers.DateField()publisher = PublisherSerializer(read_only=True)publisher_id = serializers.IntegerField(write_only=True)author = AuthorSerializer(many=True, read_only=True)author_list = serializers.ListField(write_only=True) #def create(self, validated_data): # 創建數據book = Book.objects.create(title=validated_data["title"], category=validated_data["w_category"],pub_time=validated_data["pub_time"], publisher_id=validated_data["publisher_id"])book.author.add(*validated_data["author_list"]) # 多對多return book #def update(self, instance, validated_data): # 處理 put 更新數據instance.title = validated_data.get("title", instance.title)instance.category = validated_data.get("category", instance.category)instance.pub_time = validated_data.get("pub_time", instance.pub_time)instance.publisher_id = validated_data.get("publisher_id", instance.publisher_id)if validated_data.get("author_list"):instance.author.set(validated_data["author_list"])instance.save()return instancedef validate_title(self, value): # 對傳過來的title進行校驗if "python" not in value.lower():raise serializers.ValidationError("標題必須含有python")return valuedef validate(self, attrs):if attrs["w_category"] == 1 and attrs["publisher_id"] == 1:return attrselse:raise serializers.ValidationError("分類以及標題不符合要求") serializers.SerializerModelSerializer序列化
現在我們已經清楚了Serializer的用法,會發現我們所有的序列化跟我們的模型都緊密相關~
那么,DRF也給我們提供了跟模型緊密相關的序列化器ModelSerializer
-- 它會根據模型自動生成一組字段
-- 它簡單的默認實現了.update()以及.create()方法
# 注意:當序列化類MATE中定義了depth時,這個序列化類中引用字段(外鍵)則自動變為只讀class BookSerializer(serializers.ModelSerializer):class Meta:model = Bookfields = "__all__"# fields = ["id", "title", "pub_time"]# exclude = ["user"]# 分別是所有字段 包含某些字段 排除某些字段depth = 1 # depth 代表找嵌套關系的第幾層 外鍵關系的序列化 # depth = 1 #對第二級別的字段也進行序列化 class BookSerializer(serializers.ModelSerializer):category = serializers.CharField(source="get_category_display")class Meta:model = Book # 對應的 model# fields = ["id", "title", "pub_time"]fields = "__all__"? # 所有字段depth = 1? # 外鍵深度為1拿到了較多的冗余字段
通過 SerializerMethodField 只取想要的字段,然后在下面定義各自的獲取方法
自定義字段
class BookSerializer(serializers.ModelSerializer):# 只取想要的字段,category_display = serializers.SerializerMethodField(read_only=True)publisher_info = serializers.SerializerMethodField(read_only=True)authors = serializers.SerializerMethodField(read_only=True)def get_category_display(self, obj):return obj.get_category_display()def get_authors(self, obj):authors_query_set = obj.author.all()return [{"id": author_obj.id, "name": author_obj.name} for author_obj in authors_query_set]def get_publisher_info(self, obj):# obj 是我們序列化的每個Book對象publisher_obj = obj.publisherreturn {"id": publisher_obj.id, "title": publisher_obj.title}Meta中其它關鍵字參數
class BookSerializer(serializers.ModelSerializer):chapter = serializers.CharField(source="get_chapter_display", read_only=True)class Meta:model = Bookfields = "__all__"# fields = ["id", "title", "pub_time"]# exclude = ["user"]# 分別是所有字段 包含某些字段 排除某些字段depth = 1read_only_fields = ["id"]extra_kwargs = {"title": {"validators": [my_validate,]}} Meta中其它關鍵字參數 由于depth會讓我們外鍵變成只讀,所以我們再定義一個序列化的類,其實只要去掉depth就可以了~~class BookSerializer(serializers.ModelSerializer):chapter = serializers.CharField(source="get_chapter_display", read_only=True)class Meta:model = Bookfields = "__all__"# fields = ["id", "title", "pub_time"]# exclude = ["user"]# 分別是所有字段 包含某些字段 排除某些字段read_only_fields = ["id"]extra_kwargs = {"title": {"validators": [my_validate,]}} post以及patch請求?ModelSerializer反序列化
ModelSerializer 默認已經幫我們做了反序列化(不用寫 create 方法)接受post 數據
class BookSerializer(serializers.ModelSerializer):# 只取想要的字段,category_display = serializers.SerializerMethodField(read_only=True) # 序列化(顯示的時候)的 顯示publisher_info = serializers.SerializerMethodField(read_only=True)authors = serializers.SerializerMethodField(read_only=True)# 定義獲取字段的方法def get_category_display(self, obj):return obj.get_category_display()def get_authors(self, obj):authors_query_set = obj.author.all()return [{"id": author_obj.id, "name": author_obj.name} for author_obj in authors_query_set]def get_publisher_info(self, obj):# obj 是我們序列化的每個Book對象publisher_obj = obj.publisherreturn {"id": publisher_obj.id, "title": publisher_obj.title}# category = serializers.CharField(source="get_category_display")class Meta:model = Book # 對應的 model# fields = ["id", "title", "pub_time"]fields = "__all__"# depth = 1# 字段的額外參數, "write_only": True 讓下面這字段在反序列化的時候顯示extra_kwargs = {"category": {"write_only": True}, "publisher": {"write_only": True},"author": {"write_only": True}} serializers.ModelSerializer from rest_framework import serializers from .models import Book# 外鍵序列化 class PublisherSerializer(serializers.Serializer):id = serializers.IntegerField()title = serializers.CharField(max_length=32)class AuthorSerializer(serializers.Serializer):id = serializers.IntegerField()name = serializers.CharField(max_length=32)# # # 傳過來的書籍對象數據 # book_obj = { # "title": "Alex的使用教程", # "w_category": 1, # "pub_time": "2018-10-09", # "publisher_id": 1, # "author_list": [1, 2] # } # # data = { # "title": "Alex的使用教程2" # }def my_validate(value): # 自定義驗證器,權重更高,if "敏感信息" in value.lower():raise serializers.ValidationError("不能含有敏感信息")else:return value# class BookSerializer(serializers.Serializer): # id = serializers.IntegerField(required=False) # 不需要校驗 # title = serializers.CharField(max_length=32, validators=[my_validate]) # CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux")) # category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True) # w_category = serializers.ChoiceField(choices=CHOICES, write_only=True) # pub_time = serializers.DateField() # # publisher = PublisherSerializer(read_only=True) # publisher_id = serializers.IntegerField(write_only=True) # author = AuthorSerializer(many=True, read_only=True) # author_list = serializers.ListField(write_only=True) # # def create(self, validated_data): # 創建數據 # book = Book.objects.create(title=validated_data["title"], category=validated_data["w_category"], # pub_time=validated_data["pub_time"], publisher_id=validated_data["publisher_id"]) # book.author.add(*validated_data["author_list"]) # 多對多 # return book # # def update(self, instance, validated_data): # 處理 put 更新數據 # instance.title = validated_data.get("title", instance.title) # instance.category = validated_data.get("category", instance.category) # instance.pub_time = validated_data.get("pub_time", instance.pub_time) # instance.publisher_id = validated_data.get("publisher_id", instance.publisher_id) # if validated_data.get("author_list"): # instance.author.set(validated_data["author_list"]) # instance.save() # return instance # # def validate_title(self, value): # 對傳過來的title進行校驗 # if "python" not in value.lower(): # raise serializers.ValidationError("標題必須含有python") # return value # # def validate(self, attrs): # if attrs["w_category"] == 1 and attrs["publisher_id"] == 1: # return attrs # else: # raise serializers.ValidationError("分類以及標題不符合要求")# 方法二 class BookSerializer(serializers.ModelSerializer):# 只取想要的字段,category_display = serializers.SerializerMethodField(read_only=True) # 序列化(顯示的時候)的 顯示publisher_info = serializers.SerializerMethodField(read_only=True)authors = serializers.SerializerMethodField(read_only=True)# 定義獲取字段的方法def get_category_display(self, obj):return obj.get_category_display()def get_authors(self, obj):authors_query_set = obj.author.all()return [{"id": author_obj.id, "name": author_obj.name} for author_obj in authors_query_set]def get_publisher_info(self, obj):# obj 是我們序列化的每個Book對象publisher_obj = obj.publisherreturn {"id": publisher_obj.id, "title": publisher_obj.title}# category = serializers.CharField(source="get_category_display")class Meta:model = Book # 對應的 model# fields = ["id", "title", "pub_time"]fields = "__all__"# depth = 1# 字段的額外參數, "write_only": True 反序列化的時候顯示extra_kwargs = {"category": {"write_only": True}, "publisher": {"write_only": True},"author": {"write_only": True}} serializers.py序列化組件小結
總結
以上是生活随笔為你收集整理的drf3 Serializers 序列化组件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: drf2 FBV和CBV
- 下一篇: drf4 视图与路由组件