模型类序列化器ModelSerializer

如果我们想要使用序列化器对应的是Django的模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类。

ModelSerializer与常规的Serializer相同,但提供了:

  • 基于模型类自动生成一系列字段
  • 基于模型类自动为Serializer生成validators,比如unique_together
  • 包含默认的create()和update()的实现

1. 定义

比如我们创建一个BookInfoSerializer:

class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = BookInfo  # 指定生成字段的模型类
        fields = '__all__'  # 表示包含所有的字段
  • model 指明参照哪个模型类
  • fields 指明为模型类的哪些字段生成

我们可以在python manage.py shell中查看自动生成的BookModelSerializer的具体实现

>>> from book_drf.serializer import BookModelSerializer
>>> BookModelSerializer()
BookModelSerializer():
    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)

2. 指定字段

1) 使用fields来明确字段,__all__表示包含所有字段,也可以写明具体哪些字段,如

class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = BookInfo  # 指定生成字段的模型类
        # fields = '__all__'  # 表示包含所有的字段
        fields = ('btitle', 'bread')  # 指定模型类中的字段

 我们可以在python manage.py shell中查看自动生成的BookModelSerializer的具体实现

>>> from book_drf.serializer import BookModelSerializer
>>> BookModelSerializer()
BookModelSerializer():
    btitle = CharField(label='名称', max_length=20)
    bread = IntegerField(label='阅读量', max_value=2147483647, min_value=-2147483648, required=False)

2) 使用exclude可以明确排除掉哪些字段

class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = BookInfo  # 指定生成字段的模型类
        # fields = '__all__'  # 表示包含所有的字段
        # fields = ('btitle', 'bread')  # 指定模型类中的字段
        # exclude 表示排除掉哪些字段
        exclude = ('btitle',)  # 元组只有一个的时候,注意后面需要加一个逗号(,)

我们可以在python manage.py shell中查看自动生成的BookModelSerializer的具体实现

BookModelSerializer():
    id = IntegerField(label='ID', read_only=True)
    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)

从上面的显示结果,我们发现已经没有btitle这个字段信息了,已经排除掉了

修改增加选项参数的使用

通过上面的显示结果,我们发现

bread = IntegerField(label='阅读量', max_value=2147483647, min_value=-2147483648, required=False)

这个不是我们想要的结果,如何修改相关的参数呢?

3) 显示指明字段,如下面代码:

class BookModelSerializer(serializers.ModelSerializer):
    # 显示指明字段
    bread = serializers.IntegerField(max_value=100, min_value=20)
    class Meta:
        model = BookInfo  # 指定生成字段的模型类
        fields = '__all__'  # 表示包含所有的字段
        # fields = ('btitle', 'bread')  # 指定模型类中的字段
        # exclude 表示排除掉哪些字段
        # exclude = ('btitle',)  # 元组只有一个的时候,注意后面需要加一个逗号(,)

 我们可以在python manage.py shell中查看自动生成的BookModelSerializer的具体实现

BookModelSerializer():
    id = IntegerField(label='ID', read_only=True)
    bread = IntegerField(max_value=100, min_value=20)
    btitle = CharField(label='名称', max_length=20)
    bpub_date = DateField(label='发布日期')
    bcomment = IntegerField(label='评论量', max_value=2147483647, min_value=-2147483648, required=False)

通过显示指明字段的方式成功的修改了字段的信息

bread = IntegerField(max_value=100, min_value=20)

添加额外参数

我们可以使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数

class BookModelSerializer(serializers.ModelSerializer):
    # 显示指明字段
    bread = serializers.IntegerField(max_value=100, min_value=20)
    class Meta:
        model = BookInfo  # 指定生成字段的模型类
        fields = '__all__'  # 表示包含所有的字段
        # fields = ('btitle', 'bread')  # 指定模型类中的字段
        # exclude 表示排除掉哪些字段
        # exclude = ('btitle',)  # 元组只有一个的时候,注意后面需要加一个逗号(,)
        # 添加修改字段选项参数
        extra_kwargs={
            "bcomment":{
                'max_value':100
            },
            'btitle':{
                'min_length':5
            }
        }

 我们可以在python manage.py shell中查看自动生成的BookModelSerializer的具体实现

>>> from book_drf.serializer import BookModelSerializer
>>> BookModelSerializer()
BookModelSerializer():
    id = IntegerField(label='ID', read_only=True)
    bread = IntegerField(max_value=100, min_value=20)
    btitle = CharField(label='名称', max_length=20, min_length=5)
    bpub_date = DateField(label='发布日期')
    bcomment = IntegerField(label='评论量', max_value=100, min_value=-2147483648, required=False)
    is_delete = BooleanField(label='逻辑删除', required=False)

分析 btitle = models.CharField(max_length=20, verbose_name='名称')

通过 extra_kwargs 修改 当没有 'min_length':5 这个属性时,会增加,当有这个属性时会修改

btitle = CharField(label='名称', max_length=20, min_length=5)

当模型类中没有这个字段时,如何增加这个字段,需要显示指明字段,如下面代码:

class BookModelSerializer(serializers.ModelSerializer):
    # 显示指明字段
    bread = serializers.IntegerField(max_value=100, min_value=20)
    # 模型类没有的字段,增加字段时,需要显示指明字段
    sms_code = serializers.CharField(max_length=6, min_length=6)
    class Meta:
        model = BookInfo  # 指定生成字段的模型类
        fields = '__all__'  # 表示包含所有的字段
        # fields = ('btitle', 'bread')  # 指定模型类中的字段
        # exclude 表示排除掉哪些字段
        # exclude = ('btitle',)  # 元组只有一个的时候,注意后面需要加一个逗号(,)
        # 添加修改字段选项参数
        # extra_kwargs={
        #     "bcomment":{
        #         'max_value':100
        #     },
        #     'btitle':{
        #         'min_length':5
        #     }
        # }

 我们可以在python manage.py shell中查看自动生成的BookModelSerializer的具体实现

>>> from book_drf.serializer import BookModelSerializer
>>> BookModelSerializer()
BookModelSerializer():
    id = IntegerField(label='ID', read_only=True)
    bread = IntegerField(max_value=100, min_value=20)
    sms_code = CharField(max_length=6, min_length=6)
    btitle = CharField(label='名称', max_length=20)
    bpub_date = DateField(label='发布日期')
    bcomment = IntegerField(label='评论量', max_value=2147483647, min_value=-2147483648, required=False)
    is_delete = BooleanField(label='逻辑删除', required=False)

我们发现上面显示的结果,增加了 sms_code = CharField(max_length=6, min_length=6) 这个字段信息

注意事项:

fields = ('btitle', 'bread') # 指定模型类中的字段

这种精确指定字段,必须包含显示指明字段,否则会报如下错误信息:

AssertionError                            Traceback (most recent call last)
~\AppData\Local\Programs\Python\Python36\lib\site-packages\IPython\core\formatters.py in __call__(self, obj)
    700                 type_pprinters=self.type_printers,
    701                 deferred_pprinters=self.deferred_printers)
--> 702             printer.pretty(obj)
    703             printer.flush()
    704             return stream.getvalue()

~\AppData\Local\Programs\Python\Python36\lib\site-packages\IPython\lib\pretty.py in pretty(self, obj)
    392                         if cls is not object \
    393                                 and callable(cls.__dict__.get('__repr__')):
--> 394                             return _repr_pprint(obj, self, cycle)
    395
    396             return _default_pprint(obj, self, cycle)

~\AppData\Local\Programs\Python\Python36\lib\site-packages\IPython\lib\pretty.py in _repr_pprint(obj, p, cycle)
    698     """A pprint that just redirects to the normal repr function."""
    699     # Find newlines and replace them with p.break_()
--> 700     output = repr(obj)
    701     lines = output.splitlines()
    702     with p.group():

~\AppData\Local\Programs\Python\Python36\lib\site-packages\rest_framework\serializers.py in __repr__(self)
    521
    522     def __repr__(self):
--> 523         return representation.serializer_repr(self, indent=1)
    524
    525     # The following are used for accessing `BoundField` instances on the

~\AppData\Local\Programs\Python\Python36\lib\site-packages\rest_framework\utils\representation.py in serializer_repr(serializer, indent, forc
e_many)
     75         fields = force_many.fields
     76     else:
---> 77         fields = serializer.fields
     78
     79     for field_name, field in fields.items():

~\AppData\Local\Programs\Python\Python36\lib\site-packages\django\utils\functional.py in __get__(self, instance, cls)
     46         if instance is None:
     47             return self
---> 48         res = instance.__dict__[self.name] = self.func(instance)
     49         return res
     50

~\AppData\Local\Programs\Python\Python36\lib\site-packages\rest_framework\serializers.py in fields(self)
    347         # even if Django's app-loading stage has not yet run.
    348         fields = BindingDict(self)
--> 349         for key, value in self.get_fields().items():
    350             fields[key] = value
    351         return fields

~\AppData\Local\Programs\Python\Python36\lib\site-packages\rest_framework\serializers.py in get_fields(self)
   1027         # Retrieve metadata about fields & relationships on the model class.
   1028         info = model_meta.get_field_info(model)
-> 1029         field_names = self.get_field_names(declared_fields, info)
   1030
   1031         # Determine any extra field arguments and hidden fields that

~\AppData\Local\Programs\Python\Python36\lib\site-packages\rest_framework\serializers.py in get_field_names(self, declared_fields, info)
   1128                     "'fields' option.".format(
   1129                         field_name=field_name,
-> 1130                         serializer_class=self.__class__.__name__
   1131                     )
   1132                 )

AssertionError: The field 'sms_code' was declared on serializer BookModelSerializer, but has not been included in the 'fields' option.

精确指定字段,必须包含显示指明字段,正确代码如下:

class BookModelSerializer(serializers.ModelSerializer):
    # 显示指明字段
    btitle = serializers.IntegerField(max_value=100, min_value=20)
    # 模型类没有的字段,增加字段时,需要显示指明字段
    sms_code = serializers.CharField(max_length=6, min_length=6)
    class Meta:
        model = BookInfo  # 指定生成字段的模型类
        # fields = '__all__'  # 表示包含所有的字段
        fields = ('btitle', 'bread', 'sms_code')  # 精确指定的字段
        # exclude 表示排除掉哪些字段
        # exclude = ('btitle',)  # 元组只有一个的时候,注意后面需要加一个逗号(,)
        # 添加修改字段选项参数
        # extra_kwargs={
        #     "bcomment":{
        #         'max_value':100
        #     },
        #     'btitle':{
        #         'min_length':5
        #     }
        # }

 我们可以在python manage.py shell中查看自动生成的BookModelSerializer的具体实现

>>> from book_drf.serializer import BookModelSerializer
>>> BookModelSerializer()
BookModelSerializer():
    btitle = IntegerField(max_value=100, min_value=20)
    bread = IntegerField(label='阅读量', max_value=2147483647, min_value=-2147483648, required=False)
    sms_code = CharField(max_length=6, min_length=6)

4) 指明只读字段

可以通过read_only_fields指明只读字段,即仅用于序列化输出的字段

class BookModelSerializer(serializers.ModelSerializer):
    # 显示指明字段
    btitle = serializers.IntegerField(max_value=100, min_value=20)
    # 模型类没有的字段,增加字段时,需要显示指明字段
    sms_code = serializers.CharField(max_length=6, min_length=6)
    class Meta:
        model = BookInfo  # 指定生成字段的模型类
        # fields = '__all__'  # 表示包含所有的字段
        fields = ('btitle', 'bread', 'sms_code')  # 精确指定的字段
        read_only_fields = ('bread',)  # 指明只读字段
        # exclude 表示排除掉哪些字段
        # exclude = ('btitle',)  # 元组只有一个的时候,注意后面需要加一个逗号(,)
        # 添加修改字段选项参数
        # extra_kwargs={
        #     "bcomment":{
        #         'max_value':100
        #     },
        #     'btitle':{
        #         'min_length':5
        #     }
        # }

 我们可以在python manage.py shell中查看自动生成的BookModelSerializer的具体实现

>>> from book_drf.serializer import BookModelSerializer
>>> BookModelSerializer()
BookModelSerializer():
    btitle = IntegerField(max_value=100, min_value=20)
    bread = IntegerField(label='阅读量', read_only=True)
    sms_code = CharField(max_length=6, min_length=6)