DRF序列化

1、安裝 Django REST framework 框架

使用命令:pip install djangorestframework前端

2、在setings裏面註冊

INSTALLED_APPS = [
"rest_framework"
]

Serializers 序列化組件

 

爲何要用序列化組件

當咱們作先後端分離的項目~~咱們先後端交互通常都選擇JSON數據格式,JSON是一個輕量級的數據交互格式。python

那麼咱們給前端數據的時候都要轉成json格式,那就須要對咱們從數據庫拿到的數據進行序列化。linux

Django的序列化方法

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序列化的方法

首先,咱們要用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, ])

ModelSerializer

如今咱們已經清楚了Serializer的用法,會發現咱們全部的序列化跟咱們的模型都緊密相關~

那麼,DRF也給咱們提供了跟模型緊密相關的序列化器~~ModelSerializer~~

  -- 它會根據模型自動生成一組字段

  -- 它簡單的默認實現了.update()以及.create()方法

定義一個ModelSerializer序列化器

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)
相關文章
相關標籤/搜索