我有一些这样的模型:
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')
可以吗?
正如 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
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')
现在您可以为每个模型正常使用这两个序列化器。
但是,如果您确实想为这两个模型都使用一个序列化器,那么也为他创建一个容器模型和一个序列化器。这样干净多了:)
不能将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)
可以跳过 TypeBaseSerializer 的模型;
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