python - instalar - django rest framework serie de clases abstractas
django rest swagger (3)
Creo que el siguiente enfoque es más limpio. Puede establecer el campo "abstracto" en true para el serializador base y agregar su lógica común para todos los serializadores secundarios.
class TypeBaseSerializer(serializers.Serializer):
class Meta:
model = TypeBase
fields = (''id'', ''name'')
abstract = True
def func(...):
# ... some logic
Y luego cree serializadores secundarios y úselos para la manipulación de datos.
class PersonTypeSerializer(TypeBaseSerializer):
class Meta:
model = PersonType
fields = (''id'', ''name'')
class CompanyTypeSerializer(TypeBaseSerializer):
class Meta:
model = CompanyType
fields = (''id'', ''name'')
Ahora puede usar los dos serializadores normalmente para cada modelo.
Pero si realmente desea tener un serializador para ambos modelos, cree un modelo de contenedor y un serializador para él también. Eso es mucho más limpio :)
Tengo algunos modelos como estos:
class TypeBase(models.Model):
name = models.CharField(max_length=20)
class Meta:
abstract=True
class PersonType(TypeBase):
pass
class CompanyType(TypeBase):
pass
Teniendo esto, quiero crear solo un serializador que contenga todos estos tipos de campo (serialización, deserialización, actualización y guardado).
Para ser más específico, solo quiero un serializador (TypeBaseSerializer) que imprima el menú desplegable en la interfaz de usuario, serialice la respuesta json, deserialícela en la publicación y guárdela para todos mis tipos basados.
Algo como esto:
class TypeBaseSerializer(serializers.Serializer):
class Meta:
model = TypeBase
fields = (''id'', ''name'')
¿Es posible?
No puede usar un ModelSerializer
con un modelo base abstracto. Desde restframework.serializers:
if model_meta.is_abstract_model(self.Meta.model):
raise ValueError(
''Cannot use ModelSerializer with Abstract Models.''
)
Escribí una función serializer_factory para un problema similar:
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
Luego puede usar la fábrica para producir serializadores según sea necesario:
def typebase_serializer_factory(mdl):
myserializer = serializer_factory(
mdl,fields=["id","name"],
#owner=HiddenField(default=CurrentUserDefault()),#Optional additional configuration for subclasses
)
return myserializer
Ahora instanciar diferentes serializadores de subclase:
persontypeserializer = typebase_serializer_factory(PersonType)
companytypeserializer = typebase_serializer_factory(CompanyType)
Simplemente iterando un poco sobre la respuesta de @ adki:
- es posible omitir el modelo para TypeBaseSerializer;
- Los serializadores derivados pueden hacer referencia a TypeBaseSerializer.meta.fields, por lo que los cambiaría en un solo lugar.
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