使用命令:pip install djangorestframework前端
INSTALLED_APPS = [ "rest_framework" ]
當咱們作先後端分離的項目~~咱們先後端交互通常都選擇JSON數據格式,JSON是一個輕量級的數據交互格式。python
那麼咱們給前端數據的時候都要轉成json格式,那就須要對咱們從數據庫拿到的數據進行序列化。linux
from django.shortcuts import render from django.views import View from django.http import HttpResponse, JsonResponse from .models import Book, Publisher from django.core import serializers from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import serializers from .serializers import BookSerializer import json class BookView(View): 初版用.values實現序列化 def get(self, request): book_queryset = Book.objects.values("id", "title", "pub_time", "publisher") # queryset [{}, {}] book_list = list(book_queryset) ret = json.dumps(book_list, ensure_ascii=False)#沒法序列化datetime數據類型 return HttpResponse(ret) ret = [] for book in book_list: publisher_obj = Publisher.objects.filter(id=book["publisher"]).first() book["publisher"] = { "id": publisher_obj.id, "title": publisher_obj.title } ret.append(book) return JsonResponse(ret, safe=False, json_dumps_params={"ensure_ascii": False})#注意和json.dumps的ensure_ascii區別 第二版 用Django自帶的序列化模塊依然沒法完成序列化外鍵關係,只能序列化模型 def get(self, request): book_queryset = Book.objects.all() ret = serializers.serialize("json", book_queryset, ensure_ascii=False) return HttpResponse(ret)
首先,咱們要用DRF的序列化,就要遵循人家框架的一些標準,數據庫
-- Django咱們CBV繼承類是View,如今DRF咱們要用APIViewdjango
-- Django中返回的時候咱們用HTTPResponse,JsonResponse,render ,DRF咱們用Responsejson
from rest_framework import serializers from .models import Book class BookSerializer(serializers.Serializer): id = serializers.IntegerField(required=False)#這個字段不須要校驗 title = serializers.CharField(max_length=32) pub_time = serializers.DateField() # CHOICES = ((1, "python"), (2, "linux"), (3, "go")) # category = serializers.ChoiceField(choices=CHOICES) #"get_category_display"顯示對應序號的中文 category = serializers.CharField(source="get_category_display", read_only=True)#注意ChoiceField改爲CharField,這個字段正序用 post_category = serializers.IntegerField(write_only=True)#這個字段只反序用 publisher = PublisherSerializer(read_only=True) authors = AuthorSerializer(many=True, read_only=True)#author和book是多對多關係,因此many=True publisher_id = serializers.IntegerField(write_only=True) author_list = serializers.ListField(write_only=True) def create(self, validated_data): #經過ORM操做給Book表增長數據 print(validated_data)#字典類型 book_obj = Book.objects.create(title=validated_data["title"], pub_time=validated_data["pub_time"], category=validated_data["post_category"], publisher_id=validated_data["publisher_id"]) book_obj.authors.add(*validated_data["author_list"])#多對多不須要save return book_obj
class BooksView(APIView): def get(self, request): # print(request._request) book_queryset = Book.objects.all() # 聲明一個序列化器 # 用序列化器去序列化queryset ser_obj = BookSerializer(book_queryset, many=True) # 若是是多個book_queryset必須聲明:many=True # 序列化好的數據在data裏面 return Response(ser_obj.data)
APIView和View區別
-- APIView繼承了View
-- 豁免csrf
-- 封裝了request 用Request
-- _request是舊的request
-- request.query_params == _request.GET
-- request.data == _request.POST _request.Files 除了GET的全部的信息
當前端給咱們發post的請求的時候~前端給咱們傳過來的數據~咱們要進行一些校驗而後保存到數據庫~後端
這些校驗以及保存工做,DRF的Serializer也給咱們提供了一些方法了~~app
首先~咱們要寫反序列化用的一些字段~有些字段要跟序列化區分開~~框架
Serializer提供了.is_valid() 和.save()方法~~前後端分離
class BookView(APIView): def get(self, request): book_list = Book.objects.all() ret = BookSerializer(book_list, many=True) return Response(ret.data) def post(self, request): # book_obj = request.data print(request.data) serializer = BookSerializer(data=request.data) if serializer.is_valid(): print(12341253) serializer.save() return Response(serializer.validated_data) else: return Response(serializer.errors) 反序列化views.py
class BookSerializer(serializers.Serializer): id = serializers.IntegerField(read_only=True) title = serializers.CharField(max_length=32) # 省略了一些字段 跟上面代碼裏同樣的 # 。。。。。 def validate_title(self, value): if "python" not in value.lower(): raise serializers.ValidationError("標題必須含有Python") return value 單個字段的驗證
def my_validate(value): if "敏感詞彙" in value.lower: raise serializers.ValidationError("包含敏感詞彙,請從新提交") return value class BookSerializer(serializers.Serializer): id = serializers.IntegerField(read_only=True) title = serializers.CharField(max_length=32, validators=[my_validate]) # 。。。。。。 自定義字段 驗證器 validators
def validate(self, attrs): # attrs 是前端傳過來的全部的數據組成的字典 if "python" in attrs["title"] and attrs["post_category"] == 1: return attrs raise serializers.ValidationError("輸入的圖書名字或者分類不合法")
#多個字段
序列化組件 驗證
單個字段校驗 低於自定義權重
def validate_xxxxx(self, value):
raise serializers.ValidationError("xxxxx")
return value
多個字段 權重最低
def validate(self, attrs):
attrs 前端傳過來的全部的數據組成的字典
raise serializers.ValidationError("xxxxx")
return attrs
自定義 權重最高
def my_validate(value):
raise serializers.ValidationError("xxxxx")
return value
title = serializers.CharField(max_length=32, validators=[my_validate, ])
如今咱們已經清楚了Serializer的用法,會發現咱們全部的序列化跟咱們的模型都緊密相關~
那麼,DRF也給咱們提供了跟模型緊密相關的序列化器~~ModelSerializer~~
-- 它會根據模型自動生成一組字段
-- 它簡單的默認實現了.update()以及.create()方法
class BookSerializer(serializers.ModelSerializer): category_text = serializers.SerializerMethodField(read_only=True) publisher_info = serializers.SerializerMethodField(read_only=True) author_info = serializers.SerializerMethodField(read_only=True) # 方法字段 # SerializerMethodField 會去找鉤子方法 鉤子方法的返回值給這個字段 只用於正序 # get_字段名稱 # create update 方法自帶 def get_category_text(self, obj): # obj就是序列化的每一個模型對象 book_obj return obj.get_category_display() def get_publisher_info(self, obj): return {"id": obj.publisher_id, "title": obj.publisher.title} def get_author_info(self, obj): return [{"id": author.id, "name": author.name} for author in obj.authors.all()] class Meta: model = Book fields = "__all__" # fields = ["id", "title", "pub_time"] # exclude = ["authors"] # depth = 1 只跨一張表 # depth 讓你全部的外鍵關係變成read_only=True,數字顯示對應的文字 # extra_kwargs 給默認字段加額外的參數 extra_kwargs = {"category": {"write_only": True}, "publisher": {"write_only": True}, "authors": {"write_only": True}}
序列化組件 -- 序列化 -- 聲明一個序列化器 class BookSerializer(serializers.Serializer): id = serializers.IntegerField(required=False) title = serializers.CharField(max_length=32) pub_time = serializers.DateField() -- 視圖裏序列化咱們的queryset ser_obj = BookSerializer(queryset, many=True) return Response(ser_obj.data) -- 實現流程 -- 若是指定了many=True -- 把queryset當成可迭代對象去循環 獲得每一個模型對象 -- 把每一個模型對象放入序列號器進行序列化 -- 進行字段匹配 匹配上的字段進行序列化 匹配不上丟棄 -- 必須知足序列化的全部字段要求 -- 反序列化 -- 獲取前端傳過來的數據 -- 用序列化器進行校驗 ser_obj = BookSerializer(data=request.data) if ser_obj.is_valid(): ser_obj.save()# 調用create方法 return Response(ser_obj.data) else: return Response(ser_obj.errors) -- 寫create方法 在create方法裏用ORM操做建立新對象 -- 序列化以及反序列化的時候字段類型不統一的狀況 -- required=False 這個字段不須要校驗 -- read_only=True 這個字段正序用 -- write_only=True 這個字段只反序用 --partial = True 部分更新 --"get_category_display"顯示對應序號的中文 -- 視圖 ser_obj = BookSerializer(data=request.data) if ser_obj.is_valid(): # 校驗經過的數據在ser_obj.validated_data ser_obj.save() return Response(ser_obj.data) return Response(ser_obj.errors)