序列化

序列化

一、二次封裝Response

咱們在views.py中不論是增刪改查操做後都要經過Response返回status,msg或者網絡狀態碼與狀態信息和外界傳來的數據,所以咱們能夠將這些所有封裝到一個類中數據庫

新建response.py文件django

from rest_framework.response import Response
​
# 自定義response類
class APIResponse(Response):
    def __int__(self, status=0, msg='ok', http_status=None, headers=None,
                 exception=False, **kwargs):
        # 將外界傳來的數據存儲在kwargs中,外界傳來的數據狀態碼,狀態信息及其餘額外字段都格式化成data數據
        data= {
            'status': status,
            'msg': msg
        }
        if kwargs:
            data.update(kwargs)
        # 繼承原有的網絡狀態碼及狀態信息
        super().__init__(data=data, status=http_status, headers=headers, exception=exception)

使用:在views中直接使用默認就是{"status": 0, "msg": "ok"}api

# APIResponse() 表明就返回 {"status": 0, "msg": "ok"}
# APIResponse(result="結果") 表明返回 {"status": 0, "msg": "ok", "result": "結果"}
# APIResponse(status=1, msg='error', http_status=400, exception=True) 異常返回 {"status": 1, "msg": "error"}

二、數據庫關係分析

一、兩張表之間有關係的,進行增刪改的操做的時候都會相互影響(效率低),查詢操做正常網絡

二、有關係的兩張表,斷開關聯,但原來的數據保持與原來一致,每張表均可以單獨操做,增刪改操做效率極高,可是容易出現髒數據(開發中能夠避免),因爲數據沒有任何變化,查詢操做不會受影響app

三、Django的ORM支持斷關聯操做關係表,且全部的操做方式與沒有斷開關聯操做一致post

三、ORM操做關係

一、外鍵位置

一、一對多:外鍵字段ForeignKey必須在多的一方,書與出版社,外鍵在書表中測試

二、多對多:ManyToManyField放在任何一方均可以,由於會建立第三張關係表,用兩個外鍵分別關聯兩個表spa

三、一對一:OneToOneField放在依賴的表,做者與做者詳情,放在詳情表中,OneToOneField也能夠轉換成 外鍵 + 惟一約束rest

二、ORM關係Field

一、ForeignKey能夠設置related_name,db_constraint,on_deletecode

二、OneToOneField能夠設置related_name,db_constraint,on_delete

三、ManyToManyField能夠設置related_name,db_constraint

不能設置on_delete,緣由:不論是關聯在哪張表上,數據修改,都會影響到關係表(默認級聯),若是想控制,只能自定義關係表,在關係表的兩個外鍵分別設置on_delete

三、related_name,db_constraint,on_delete參數含義

一、related_name:表之間反向訪問的名字,默認是表名小寫 | 表名小寫_set,正向外鍵字段就是屬性名,反向外鍵字段就是設置的related_name

二、db_constraint:表之間的關聯關係,默認是True,表明關聯,手動設置爲False斷關聯,提升增刪改操做,且其餘操做不會受影響

三、on_delete:在Django 1.x默認就是CASCADE級聯刪除,在Django2.x下必須手動明確

四、表關係:級聯、不作任何事、設置默認值、設置空

一、做者沒,做者詳情必定沒用:CASCADE

二、做者沒,書還在:DO_NOTHING

三、部門沒,員工進入未分組部門:SET_DEFAULT (須要配合default屬性使用)

四、部門沒,員工部門的外鍵字段設爲空,SET_NULL (須要配合null=True屬性使用)

class Author(models.Model):
    name = models.CharField(max_length=64)
​
​
class AuthorDetail(models.Model):
    phone = models.CharField(max_length=11)
    # 外鍵字段設置依賴的一方
    author = models.OneToOneField(
        to=Author,
        related_name='detail',  # 反向訪問的名字
        db_constraint=False,  # 表之間的關聯,斷關聯
        on_delete=models.SET_NULL,  # 關聯的外鍵沒,設爲空
        null=True
    )

測試:

import os, django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "d_proj.settings")
django.setup()
​
from api.models import Author, AuthorDetail
​
# 測試正向反向查詢
# a1 = Author.objects.first()
# print(a1.name)
# print(a1.detail.phone)
# ad2 = AuthorDetail.objects.last()
# print(ad2.phone)
# print(ad2.author.name)
# 級聯關係測試
# ad2 = AuthorDetail.objects.last()  # type: AuthorDetail
# ad2.delete()
# Author.objects.first().delete()

四、基表

抽象出各表中共有的字段,而且不會完成數據庫遷移,必須配置abstract=True,其餘表繼承該表便可

# 基類:是抽象的(不會完成數據庫遷移),目的是提供共有字段的
class BaseModel(models.Model):
    is_delete = models.BooleanField(default=False)
    updated_time = models.DateTimeField(auto_now_add=True)
​
    class Meta:
        abstract = True  # 必須完成該配置

五、序列化類其餘設置

一、fields='__ all__' 將所有字段提供給外界(不經常使用)

class AuthorModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Author
        # 不經常使用,將所有字段提供給外界
        fields = '__all__' 

二、exclude=['is_delete', 'updated_time'] 排除指定字段,返回其餘字段,可是不能包含外鍵的反向字段(不經常使用)

class AuthorModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Author
        # 不經常使用,排除指定字段的其餘全部字段,不能自動包含 外鍵反向 字段
        exclude = ['is_delete', 'updated_time']  

三、depth自動深度,自動深度會顯示外鍵關聯的全部字段(不經常使用)

class AuthorModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Author
        # 'detail', 'books' 是 外鍵(正向|反向) 字段
        fields = ['name', 'detail', 'books']
        # 不經常使用,自動深度,自動深度會顯示外鍵關聯表的全部字段
        depth = 2  

四、子序列化:對於只有查操做的時候咱們能夠採用子序列化

  1. 子序列化的字段,必須是外鍵字段,不論是正向反向,而且多表纔有子序列化

  2. 子序列化的類必須寫在上面,而且序列化的數據是單個默認是many=False,多個數據對應時many=True

  3. 子序列化其實就是自定義序列化字段,覆蓋了原有的外鍵字段的規則,全部不能進行反序列化,只能讀不能寫入,因此只能針對只有查操做的時候採用

class AuthorDetailSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.AuthorDetail
        fields = ['phone']

class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        fields = ['name', 'price']

class AuthorModelSerializer(serializers.ModelSerializer):
    # 子序列化類必須寫在上方,而且只能對外鍵字段覆蓋,不能進行寫操做反序列化,因此只能對於只查的操做
    # 不設置read_only,至關於容許反序列化,而自己就不能反序列化,反序列化會報錯
    # 設置了read_only,反序列化不會報錯,可是新增的數據沒有外鍵字段的數據
    # books = BookModelSerializer(many=True)
    books = BookModelSerializer(many=True, read_only=True)
    # detail = AuthorDetailSerializer()
    detail = AuthorDetailSerializer(read_only=True)
    class Meta:
        model = models.Author
        fields = ['name', 'books', 'detail']

六、多表序列化與反序列化

一、外鍵字段要參與反序列化,,因此外鍵字段要設置爲write_only

二、外鍵關係須要連表序列化結果給前臺,能夠用@property來自定義連表序列化

三、字段少時能夠自定義序列化邏輯,字段多時能夠藉助序列化類子序列化來完成序列化過程

models.py

class Book(BaseModel):
    # ...
    
    @property  # @property字段默認就是read_only,且不容許修改
    def publish_name(self):
        return self.publish.name

    @property  # 1字段少能夠用自定義序列化過程
    def author_list(self):
        temp_author_list = []
        for author in self.authors.all():
            author_dic = {
                "name": author.name
            }
            try:
                author_dic['phone'] = author.detail.phone
            except:
                author_dic['phone'] = ''
            temp_author_list.append(author_dic)
        return temp_author_list

    @property  # 2字段多能夠用藉助序列化類完成序列化過程
    def read_author_list(self):
        from .serializers import AuthorModelSerializer
        return AuthorModelSerializer(self.authors.all(), many=True).data

 

serializers.py

# 輔助序列化類子序列化
class AuthorDetailModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.AuthorDetail
        fields = ['phone']

# 輔助序列化類
class AuthorModelSerializer(serializers.ModelSerializer):
    detail = AuthorDetailModelSerializer(many=False, read_only=True)
    class Meta:
        model = models.Author
        fields = ['name', 'detail']


# 主序列化類
class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        fields = ('name', 'price', 'image', 'publish', 'authors', 'publish_name', 'author_list', 'read_author_list')
        extra_kwargs = {
            'image': {
                'read_only': True,
            },
            'publish': {  # 系統原有的外鍵字段,要留給反序列化過程使用,序列化外鍵內容,用@property自定義
                'write_only': True,
            },
            'authors': {
                'write_only': True,
            }
        }

七、單增和羣增

一、如何區別是單增仍是羣增:判斷request.data是{ }單增仍是[ ]羣增

二、羣增若是有一個失敗會直接拋出異常給前臺,其餘數據也不會存入數據庫中

    # 單增羣增
    def post(self, request, *args, **kwargs):
        # 如何區別單增羣增:request.data是{}仍是[]
        if not isinstance(request.data, list):
            # 單增
            serializer = serializers.BookModelSerializer(data=request.data)
            serializer.is_valid(raise_exception=True)  # 若是校驗失敗,會直接拋異常,返回給前臺
            obj = serializer.save()
            # 爲何要將新增的對象從新序列化給前臺:序列化與反序列化數據不對等
            return APIResponse(result=serializers.BookModelSerializer(obj).data, http_status=201)
        else:
            # 羣增
            serializer = serializers.BookModelSerializer(data=request.data, many=True)
            serializer.is_valid(raise_exception=True)  # 若是校驗失敗,會直接拋異常,返回給前臺
            objs = serializer.save()
            # 爲何要將新增的對象從新序列化給前臺:序列化與反序列化數據不對等
            return APIResponse(result=serializers.BookModelSerializer(objs, many=True).data, http_status=201)
相關文章
相關標籤/搜索