django Rest框架抽象类序列化器

问题描述 投票:0回答:4

我有一些这样的模型:

class TypeBase(models.Model):
    name = models.CharField(max_length=20)
    class Meta:
        abstract=True

class PersonType(TypeBase):
    pass

class CompanyType(TypeBase):
    pass

有了这个,我只想创建一个包含所有这些字段类型(序列化、反序列化、更新和保存)的序列化器。

更具体地说,我只需要一个序列化器(TypeBaseSerializer)来在 UI 上打印下拉列表,序列化 json 响应,在发布时反序列化它并将其保存为我所有的基础类型。

类似这样的:

class TypeBaseSerializer(serializers.Serializer):
    class Meta:
        model = TypeBase
        fields = ('id', 'name')

可以吗?

python django django-rest-framework abstract-class
4个回答
24
投票

正如 Sebastian Wozny 的回答中已经提到的,您不能将 ModelSerializer 与抽象基础模型一起使用。

此外,正如其他一些答案所建议的那样,不存在诸如抽象序列化器之类的东西。因此,在序列化器的 Meta 类上设置

abstract = True
将不起作用

但是,您不需要使用

ModelSerializer

 作为基础/父序列化器。您可以使用 
Serializer
,然后利用 Django 的多重继承。这是它的工作原理:

class TypeBaseSerializer(serializers.Serializer): # Need to re-declare fields since this is not a ModelSerializer name = serializers.CharField() id = serializers.CharField() class Meta: fields = ['id', 'name'] def someFunction(self): #... will be available on child classes ... pass class PersonTypeSerializer(TypeBaseSerializer, serializers.ModelSerializer): class Meta: model = PersonType fields = TypeBaseSerializer.Meta.fields + ['another_field'] class CompanyTypeSerializer(TypeBaseSerializer, serializers.ModelSerializer): class Meta: model = CompanyType fields = TypeBaseSerializer.Meta.fields + ['some_other_field']
因此,现在由于字段 

name

id
 是在父类 (TypeBaseSerializer) 上声明的,因此它们将在 
PersonTypeSerializer
 上可用,并且由于这是 
ModelSerializer
 的子类,这些字段将从模型中填充实例。

您还可以在

SerializerMethodField

 上使用 
TypeBaseSerializer
,即使它不是 ModelSerializer。

class TypeBaseSerializer(serializers.Serializer): # you will have to re-declare fields here since this is not a ModelSerializer name = serializers.CharField() id = serializers.CharField() other_field = serializers.SerializerMethodField() class Meta: fields = ['id', 'name', 'other_field'] def get_other_field(self, instance): # will be available on child classes, which are children of ModelSerializers return instance.other_field
    

21
投票
我认为下面的方法更干净。您可以将基本序列化器的“抽象”字段设置为 true,并为所有子序列化器添加通用逻辑。

class TypeBaseSerializer(serializers.ModelSerializer): class Meta: model = TypeBase fields = ('id', 'name') abstract = True def func(...): # ... some logic

然后创建子序列化器并使用它们进行数据操作。

class PersonTypeSerializer(TypeBaseSerializer): class Meta: model = PersonType fields = ('id', 'name') class CompanyTypeSerializer(TypeBaseSerializer): class Meta: model = CompanyType fields = ('id', 'name')

现在您可以为每个模型正常使用这两个序列化器。

但是,如果您确实想为这两个模型都使用一个序列化器,那么也为他创建一个容器模型和一个序列化器。这样干净多了:)


17
投票

不能将ModelSerializer与抽象基础模型一起使用。 来自restframework.serializers:

if model_meta.is_abstract_model(self.Meta.model):
        raise ValueError(
            'Cannot use ModelSerializer with Abstract Models.'
        )

我为类似的问题编写了一个serializer_factory函数:

from collections import OrderedDict from restframework.serializers import ModelSerializer def serializer_factory(mdl, fields=None, **kwargss): """ Generalized serializer factory to increase DRYness of code. :param mdl: The model class that should be instanciated :param fields: the fields that should be exclusively present on the serializer :param kwargss: optional additional field specifications :return: An awesome serializer """ def _get_declared_fields(attrs): fields = [(field_name, attrs.pop(field_name)) for field_name, obj in list(attrs.items()) if isinstance(obj, Field)] fields.sort(key=lambda x: x[1]._creation_counter) return OrderedDict(fields) # Create an object that will look like a base serializer class Base(object): pass Base._declared_fields = _get_declared_fields(kwargss) class MySerializer(Base, ModelSerializer): class Meta: model = mdl if fields: setattr(Meta, "fields", fields) return MySerializer

然后您可以根据需要使用工厂来生产序列化器:

def typebase_serializer_factory(mdl): myserializer = serializer_factory( mdl,fields=["id","name"], #owner=HiddenField(default=CurrentUserDefault()),#Optional additional configuration for subclasses ) return myserializer

现在实例化不同的子类序列化器:

persontypeserializer = typebase_serializer_factory(PersonType) companytypeserializer = typebase_serializer_factory(CompanyType)



9
投票

可以跳过 TypeBaseSerializer 的模型;
  1. 派生序列化器可以引用 TypeBaseSerializer.Meta,因此您可以在一个地方更改它们。
class TypeBaseSerializer(serializers.Serializer): class Meta: fields = ('id', 'name', 'created') abstract = True def func(...): # ... some logic class PersonTypeSerializer(TypeBaseSerializer): class Meta: model = PersonType fields = TypeBaseSerializer.Meta.fields + ('age', 'date_of_birth') class CompanyTypeSerializer(TypeBaseSerializer): class Meta: model = CompanyType fields = TypeBaseSerializer.Meta.fields
    
© www.soinside.com 2019 - 2024. All rights reserved.