爲何要用序列化組件前端
作先後端分離的項目,咱們先後端交互通常都選擇JSON數據格式,JSON是一個輕量級的數據交互格式。
給前端數據的時候都要轉成json格式,那就須要對從數據庫拿到的數據進行序列化。
django序列化和rest_framework序列化的對比
將後端數據庫中的信息用json的格式傳給前端
數據準備python
DRFDemo/urls.py from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('books/', include("SerDemo.urls")), ] SerDemo/urls.py urlpatterns = [ path('list', BookView.as_view()), path('retrieve/<int:id>', BookEditView.as_view()), ]
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.title class Meta: verbose_name_plural = "01-圖書表" db_table = verbose_name_plural class Publisher(models.Model): title = models.CharField(max_length=32, verbose_name="出版社的名稱") def __str__(self): return self.title class Meta: verbose_name_plural = "02-出版社表" db_table = verbose_name_plural class Author(models.Model): name = models.CharField(max_length=32, verbose_name="做者的姓名") def __str__(self): return self.name class Meta: verbose_name_plural = "03-做者表" db_table = verbose_name_plural
for table in models.__all__: admin.site.register(getattr(models, table))
須要本身手動,對取出來的數據進行序列化後返回數據庫
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})
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
用DRF的序列化,要遵循框架的一些標準,json
-- Django咱們CBV繼承類是View,如今DRF咱們要用APIView後端
-- Django中返回的時候咱們用HTTPResponse,JsonResponse,render ,DRF咱們用Responsesession
安裝 pip install djangorestframeworkapp
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'SerDemo', 'rest_framework', ]
from rest_framework import serializers 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()
from rest_framework.views import APIView from 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 serializers 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) 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)
當前端給咱們發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
定義 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)
post數據
反回的結果
單條數據操做
from django.urls import path, include from .views import BookView, BookEditView urlpatterns = [ 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
反回的結果
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("分類以及標題不符合要求")
自定義驗證器
當有重疊校驗器時自定義的驗證器權重更高
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 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("分類以及標題不符合要求")
如今咱們已經清楚了Serializer的用法,會發現咱們全部的序列化跟咱們的模型都緊密相關~
那麼,DRF也給咱們提供了跟模型緊密相關的序列化器ModelSerializer
-- 它會根據模型自動生成一組字段
-- 它簡單的默認實現了.update()以及.create()方法
# 注意:當序列化類MATE中定義了depth時,這個序列化類中引用字段(外鍵)則自動變爲只讀 class BookSerializer(serializers.ModelSerializer): class Meta: model = Book fields = "__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.publisher return {"id": publisher_obj.id, "title": publisher_obj.title}
class BookSerializer(serializers.ModelSerializer): chapter = serializers.CharField(source="get_chapter_display", read_only=True) class Meta: model = Book fields = "__all__" # fields = ["id", "title", "pub_time"] # exclude = ["user"] # 分別是全部字段 包含某些字段 排除某些字段 depth = 1 read_only_fields = ["id"] extra_kwargs = {"title": {"validators": [my_validate,]}}
因爲depth會讓咱們外鍵變成只讀,因此咱們再定義一個序列化的類,其實只要去掉depth就能夠了~~ class BookSerializer(serializers.ModelSerializer): chapter = serializers.CharField(source="get_chapter_display", read_only=True) class Meta: model = Book fields = "__all__" # fields = ["id", "title", "pub_time"] # exclude = ["user"] # 分別是全部字段 包含某些字段 排除某些字段 read_only_fields = ["id"] extra_kwargs = {"title": {"validators": [my_validate,]}}
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.publisher return {"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}}
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.publisher return {"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}}