【Django Rest framework】Serializers ModelSerializer篇翻译及应用举例

内容介绍

开发项目是和 Django-ORM 相关的, 因此有应对 ORM 的 SerializersModelSerializer。

ModelSerializer

ModelSerializer 是和常规 Serializer 类一样区别在于:

  1. 将根据模型自动为生成一组字段
  2. 将自动为序列化器生成验证器, 例如 unique_together 验证器
  3. 默认实现了简单的 .create() 和 .update() 方法

默认情况下,该类上的所有模型字段都将映射到相应的序列化器字段。
模型上的任何关系都将映射到 PrimaryKeyRelatedField,
默认情况下不包括反向关系,除非按照序列化器关系文档中的明确指定包含反向关系。

基本代码块

from django.db import models
from rest_framework import serializers

class UserModel(models.Model):
    username = models.CharField(max_length=32, unique=True, null=False, blank=False)
    email = models.EmailField()

    ...

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserModel
        fields = ('id', 'username', 'email')

业务举例

指定序列化字段

通过 fields 有选择的指定序列化的字段

class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = ['id', 'account_name', 'users', 'created']

通过 fields指定全部字段

class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = '__all__'

通过 exclude 进行排除某些字段

class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        exclude = ['users']

嵌套序列化

如果模型中存在外键对象, 默认情况下使用外键 ID 包含外键对象,但你可以使用嵌套外键系列化对象进行输出,只需要提供 depth 参数,该 depth 选项应设置为整数值, 该值指示在嵌套对象需要表示的深度。

不推荐,容易在过程中把自己搞蒙

from rest_framework import serializers

class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = ['id', 'account_name', 'users', 'created']
        depth = 1

自定义声明字段

类似 ORM 一样使用字段声明,只修改模型类字段的映射字段需要自己声明一个字段,使用 source 来指明该字段与模型中的哪个字段对应即可或者可以自定义其它字段。

如果存在外键关联的情况则用 "__"来表示关系

class AccountSerializer(serializers.ModelSerializer):
    data_type = serializers.CharField(source='category__itme', read_only=True)
    groups = serializers.PrimaryKeyRelatedField(many=True)

    class Meta:
        model = Account

只读字段

声明只读字段只需要将包含在 fields 中的字段添加到 read_only_fields 中,或者在自定义字段中加入 read_only=True 进行声明。
默认情况下,已设置 editable=False 的模型字段和 AutoField 字段将设置为只读,并且不需要将其添加到 read_only_fields 选项中。

class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = ['id', 'account_name', 'users', 'created']
        read_only_fields = ['account_name']

附加参数

还有一个快捷方式允许使用 extra_kwargs 选项在指定字段上声明任意附加关键字参数和 read_only_fields 的情况一样,不需要在序列化程序上显式声明该字段。
此选项是一个字典,将字段名称映射到关键字参数的字典。如果已在序列化程序类上显式声明了该字段,则该 extra_kwargs 选项将被忽略。

class CreateUserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['email', 'username', 'password']
        extra_kwargs = {
    
    'password': {
    
    'write_only': True}}

    def create(self, validated_data):
        user = User(
            email=validated_data['email'],
            username=validated_data['username']
        )
        user.set_password(validated_data['password'])
        user.save()
        return user

HyperlinkedModelSerializer

HyperlinkedModelSerializer 类是类似于 ModelSerializer,不同之处在于使用的超链接来表示的关系,而不是主键类。
默认情况下序列化程序将包含一个 url 字段而不是主键字段。url 字段将使用 HyperlinkedIdentityField 序列化器字段表示,而模型上的任何关系都将使用 HyperlinkedRelatedField 序列化器字段表示。

class AccountSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Account
        fields = ['url', 'id', 'account_name', 'users', 'created']

实例化 HyperlinkedModelSerializer 必须在序列化器声明当前请求对象 request

serializer = AccountSerializer(queryset, context={
    
    'request': request})

将链接变成绝对的携带主机地址

http://api.example.com/accounts/1/

超链接映射关系确认

需要一种确定使用哪些视图将需要超链接到模型实例的方法。
默认情况下超链接应与匹配样式的视图名称 ‘{model_name}-detail’ 相对应并通过 pk 关键字参数查找实例对象。
可以使用 extra_kwargs 设置中的 view_name 和 lookup_field 选项之一或全部覆盖 URL 字段视图名称和查找字段:

class AccountSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Account
        fields = ['account_url', 'account_name', 'users', 'created']
        extra_kwargs = {
    
    
            'url': {
    
    'view_name': 'accounts', 'lookup_field': 'account_name'},
            'users': {
    
    'lookup_field': 'username'}
        }

在 serializer 上指定

class AccountSerializer(serializers.HyperlinkedModelSerializer):
    url = serializers.HyperlinkedIdentityField(
        view_name='accounts',
        lookup_field='slug'
    )
    users = serializers.HyperlinkedRelatedField(
        view_name='user-detail',
        lookup_field='username',
        many=True,
        read_only=True
    )

    class Meta:
        model = Account
        fields = ['url', 'account_name', 'users', 'created']

ListSerializer

如果自定义一个 ListSerializer 行为的序列化类,
并具有以下功能:

  1. 想要提供列表的特定验证, 检查一个元素与列表中的另一个元素没有冲突
  2. 自定义多个对象的创建或更新行为
    可以通过使用序列化 Meta 类上的 list_serializer_class 选项来修改在传递 many = True 时使用的类
class CustomListSerializer(serializers.ListSerializer):
    ...
class CustomSerializer(serializers.Serializer):
    ...
    class Meta:
        list_serializer_class = CustomListSerializer

实现创建多个对象

class BookListSerializer(serializers.ListSerializer):
    def create(self, validated_data):
        books = [Book(**item) for item in validated_data]
        return Book.objects.bulk_create(books)

class BookSerializer(serializers.Serializer):
    ...
    class Meta:
        list_serializer_class = BookListSerializer

在传递的多个实例对象的时候需要对应关系以及判断更新还是创建, 或者删除

from rest_framework import serializers

class BookListSerializer(serializers.ListSerializer):
    def update(self, instance, validated_data):
        # 映射逻辑:
        # id -> instance
        # id -> data item
        book_mapping = {
    
    book.id: book for book in instance}
        data_mapping = {
    
    item['id']: item for item in validated_data}

        # 创建实例或更新实例
        ret = []
        for book_id, data in data_mapping.items():
            book = book_mapping.get(book_id, None)
            if book is None:
                ret.append(self.child.create(data))
            else:
                ret.append(self.child.update(book, data))

        # 删除
        for book_id, book in book_mapping.items():
            if book_id not in data_mapping:
                book.delete()
        return ret

class BookSerializer(serializers.Serializer):
    # 需要使用主键在列表中标识元素,使用可写字段而不要使用默认的只读字段
    id = serializers.IntegerField()
    ...

    class Meta:
        list_serializer_class = BookListSerializer

动态自定义配置

如果需要动态的字段映射配置, 并不想定义多个类对象

from rest_framework import serializers

class DynamicFieldsModelSerializer(serializers.ModelSerializer):
    """
    fields参数,控制应显示字段。
    """

    def __init__(self, *args, **kwargs):
        # 不需要传参舍弃掉的fields
        fields = kwargs.pop('fields', None) # 额外注意 必须

        # 正常实例化超类
        super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)

        if fields is not None:
            # 删除所有在field参数中未指定的字段
            allowed = set(fields)
            existing = set(self.fields)
            for field_name in existing - allowed:
                self.fields.pop(field_name)

猜你喜欢

转载自blog.csdn.net/qq_20288327/article/details/112992757
今日推荐