1. 程式人生 > >DRF---Django中 模型類序列化器 ModelSerializer

DRF---Django中 模型類序列化器 ModelSerializer

關於常規的Serializer使用方法,可以參考 常規的Serializer講解


如果我們需要使用的序列化器,是對應Django的模型類,那麼,DRF已經為我們提供了ModelSerializer模型類序列化器,可以滿足我們的需求,快速建立一個Serializer類。

ModelSerializer和普通Serializer的區別

①:基於模型類自動生成一系列欄位;
②:基於模型類自動為Serializer生成validators,比如unique_together;
③:包含預設的create()和update()的實現。

現在,我們就從實際的操作中來看一下ModelSerializer,應該如何使用。

本文程式碼實現前提:我已經在子應用的models.py檔案中定義了幾個模型類

# 定義圖書模型類BookInfo
class BookInfo(models.Model):
    btitle = models.CharField(max_length=20, verbose_name='名稱')
    bpub_date = models.DateField(verbose_name='釋出日期')
    bread = models.IntegerField(default=0, verbose_name='閱讀量')
    bcomment = models.IntegerField(default=0, verbose_name='評論量')
    is_delete = models.BooleanField(default=False, verbose_name='邏輯刪除')
    image = models.ImageField(upload_to='booktest', verbose_name='圖片', null=True)
    
    def __str__(self):
        """定義每個資料物件的顯示資訊"""
        return self.btitle
#定義英雄模型類HeroInfo
class HeroInfo(models.Model):
    GENDER_CHOICES = (
        (0, 'male'),
        (1, 'female')
    )
    hname = models.CharField(max_length=20, verbose_name='名稱')
    hgender = models.SmallIntegerField(choices=GENDER_CHOICES, default=0, verbose_name='性別')
    hcomment = models.CharField(max_length=200, null=True, verbose_name='描述資訊')
    hbook = models.ForeignKey(BookInfo, on_delete=models.CASCADE, verbose_name='圖書')  # 外來鍵
    is_delete = models.BooleanField(default=False, verbose_name='邏輯刪除')

    def __str__(self):
        return self.hname

一·定義

我們現在對於BookInfo,建立一個序列化器

class BookInfoModelSerializer(serializers.ModelSerializer):
    class Meta:
        # 指明關聯的模型類
        model = BookInfo
        # 指明返回的欄位
        fields = "__all__"

我們現在對於HeroInfo,建立一個序列化器

class HeroInfoModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = HeroInfo
        fields = '__all__'

申明:

  • model 指明參照哪個模型類
  • fields 指明為模型類的哪些欄位生成

前面我們介紹了ModelSerializer的一個特性就是,可以根據模型類來決定建立的序列化器會有哪些欄位,為了驗證,我們可以看一下序列化器在不傳參的情況下,是什麼樣的:

In [3]: s = BookInfoModelSerializer()                                                                                               

In [4]: s                                                                                                                           
Out[4]: 
BookInfoModelSerializer():
    id = IntegerField(label='ID', read_only=True)
    btitle = CharField(label='名稱', max_length=20)
    bpub_date = DateField(label='釋出日期')
    bread = IntegerField(label='閱讀量', max_value=2147483647, min_value=-2147483648, required=False)
    bcomment = IntegerField(label='評論量', max_value=2147483647, min_value=-2147483648, required=False)
    is_delete = BooleanField(label='邏輯刪除', required=False)
    image = ImageField(allow_null=True, label='圖片', max_length=100, required=False)

由此可見,ModelSerializer確實可以滿足我們的需求,而不需要我們把欄位一個一個進行手敲了。

欄位的指定

(1)fields
上面我在程式碼中也標註了,fields可以指定我們定義的序列化器擁有的欄位;__all__ 是預設包含原模型類的所有欄位;當然了,我們也是可以寫明我們具體需要哪些欄位:

class BookInfoModelSerializer(serializers.ModelSerializer):
    """圖書資料序列化器"""
    class Meta:
        model = BookInfo
        fields = ('id', 'btitle', 'bpub_date')

(2)exclude
exclude的作用是可以排除哪些欄位不可以用

class BookInfoModelSerializer(serializers.ModelSerializer):
    """圖書資料序列化器"""
    class Meta:
        model = BookInfo
        exclude = ('image',)

注意:exclude和fields在一個序列化器中,只能存在一個,不然會報錯的。

(3)關聯欄位處理

ModelSerializer會預設使用主鍵作為關聯欄位,如下:

hbook = PrimaryKeyRelatedField(label='圖書', queryset=BookInfo.objects.all())

我們可以通過 depth 來簡單的設定巢狀模式:
現在將HeroInfo序列化器改成這樣:

class HeroInfoModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = HeroInfo
        fields = '__all__'
        depth = 1

然後我們的外來鍵hbook就變成這樣了:

    hbook = NestedSerializer(read_only=True):
        id = IntegerField(label='ID', read_only=True)
        btitle = CharField(label='名稱', max_length=20)
        bpub_date = DateField(label='釋出日期')
        bread = IntegerField(label='閱讀量', max_value=2147483647, min_value=-2147483648, required=False)
        bcomment = IntegerField(label='評論量', max_value=2147483647, min_value=-2147483648, required=False)
        is_delete = BooleanField(label='邏輯刪除', required=False)
        image = ImageField(allow_null=True, label='圖片', max_length=100, required=False)

注意:depth應該是整數,表明巢狀的層級數量。

(4)顯示指名欄位–包括關聯欄位的設定

參考程式碼:

class HeroInfoModelSerializer(serializers.ModelSerializer):
    hbook = BookInfoModelSerializer()
    class Meta:
        model = HeroInfo
        fields = ('id', 'hname', 'hgender', 'hcomment', 'hbook'

注意,如果想設定指名的欄位,並且指名的欄位包括關聯欄位,而且關聯欄位想通過自己設定,比如這裡的hbook = BookInfoModelSerializer() , 那麼,我們必須要在fields中寫上這個關聯欄位,不能以為外面寫了關聯欄位,裡面可以不寫,那是不行的。

(5)read_only_fields
指名只讀欄位,用於序列化的輸出

class BookInfoModelSerializer(serializers.ModelSerializer):
    """圖書資料序列化器"""
    class Meta:
        model = BookInfo
        fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
        read_only_fields = ('id', 'bread', 'bcomment')

序列化器的額外引數的傳遞

extra_kwargs引數可以新增或修改ModelSerializer原有的選項引數;

比如在上面的程式碼中,我們有一個閱讀量和評論的資料的最小值,預設是負數min_value=-2147483648,,這肯定是不合理的,所以就需要修改。

在BookInfoModelSerializer 中新增 extra_kwargs這個引數,並把想要修改的選項引數進行修改或者增加就可以了。

 extra_kwargs = {
                           'bread': {'min_value': 0, 'required': True},
                           'bcomment': {'min_value': 0, 'required': True},
        }  

修改後的資料如下:

In [3]: s = BookInfoModelSerializer()                                                                                               

In [4]: s                                                                                                                           
Out[4]: 
BookInfoModelSerializer():
    id = IntegerField(label='ID', read_only=True)
    btitle = CharField(label='名稱', max_length=20)
    bpub_date = DateField(label='釋出日期')
    bread = IntegerField(label='閱讀量', max_value=2147483647, min_value=0, required=True)
    bcomment = IntegerField(label='評論量', max_value=2147483647, min_value=0, required=True)
    is_delete = BooleanField(label='邏輯刪除', required=False)
    image = ImageField(allow_null=True, label='圖片', max_length=100, required=False)