2015-10-14 107 views
8

我有一些車型,如這些:Django的REST框架抽象類串行

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

class PersonType(TypeBase): 
    pass 

class CompanyType(TypeBase): 
    pass 

到這一點,我想只創建一個串行包含所有這些字段類型(序列化,反序列化,更新和保存)。更具體地說,我只需要一個在UI上打印Dropdown的序列化程序(TypeBaseSerializer),序列化json響應,在後期將其反序列化並將其保存爲所有基於我的類型。

事情是這樣的:

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

這可能嗎?

+0

這個討論也子類串行有用:https://github.com/tomchristie/django-rest-framework/issues/1926 – PhoebeB

回答

7

can't use a 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 

現在instanciate不同的子類序列化程序:

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

該解決方案似乎爲我的問題的工作,但有沒有辦法減少通用性?我認爲在我的情況下,我會一直知道我的類型的領域,我只需要動態地實例化它。 –

+0

您可以爲子類創建兩個序列化器。我處於有7個子類和不同串行器模式的情況,所以通用性至關重要。 –

2

我認爲以下方法更清潔。您可以將基本序列化器的「abstract」字段設置爲true,併爲所有子序列化器添加公共邏輯。

class TypeBaseSerializer(serializers.Serializer): 
    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') 

現在你可以使用這兩種串行器通常爲每個模型。

但是,如果你真的想爲兩個模型都有一個序列化器,那麼也爲他創建一個容器模型和一個序列化器。這是乾淨多了:)

0

只是迭代有點過@ adki的回答是:

  1. 有可能跳過型號爲TypeBaseSerializer;
  2. 派生序列化器可以引用TypeBaseSerializer.meta.fields,所以你可以在一個地方改變它們。
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