2015-10-14 20 views
8

मैं इस तरह के कुछ मॉडल हैं:Django बाकी ढांचे सार वर्ग serializer

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

class PersonType(TypeBase): 
    pass 

class CompanyType(TypeBase): 
    pass 

इस के बाद, मैं सिर्फ एक serializer है कि इन सभी फ़ील्ड प्रकार धारण बनाने (क्रमबद्धता, अक्रमांकन, अद्यतन और बचाने के लिए) करना चाहते हैं।

अधिक विशिष्ट होने के लिए, मुझे केवल एक सीरिएलाइज़र (TypeBaseSerializer) चाहिए जो यूआई पर ड्रॉपडाउन प्रिंट करता है, जेसन प्रतिक्रिया को क्रमबद्ध करता है, इसे पोस्ट पर deserialize और मेरे सभी आधारित प्रकारों के लिए इसे बचाने के लिए।

कुछ इस तरह:

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

क्या यह संभव है?

+0

यह भी उपवर्गीकरण serializers पर उपयोगी चर्चा: https://github.com/tomchristie/django-rest-framework/issues/1926 – PhoebeB

उत्तर

7

आप can't use एक 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 

की जरूरत के रूप में आप तब कारखाने का उपयोग serializers निर्माण करने के लिए कर सकते हैं:

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

अब विभिन्न उपclass serializers instanciate:

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

यह समाधान मेरी समस्या के लिए काम करने लगता है, लेकिन क्या कम सामान्य होने का कोई तरीका है? मुझे लगता है कि मेरे मामले में, मैं हमेशा अपने प्रकार के क्षेत्रों को जानता हूं और मुझे इसे गतिशील रूप से त्वरित करने की आवश्यकता है। –

+0

आप सबक्लास के लिए दो धारावाहिक बना सकते हैं। मैं 7 उप-वर्गों और विभिन्न धारावाहिक मोड के साथ एक परिस्थिति में था, इसलिए जेनेरिक होना महत्वपूर्ण था। –

2

मुझे लगता है कि निम्नलिखित दृष्टिकोण अधिक क्लीनर है। आप मूल धारावाहिक के लिए "अमूर्त" फ़ील्ड को सत्य में सेट कर सकते हैं और सभी बाल धारावाहिकों के लिए अपना सामान्य तर्क जोड़ सकते हैं।

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

    def func(...): 
    # ... some logic 

और फिर बच्चे serializers बना सकते हैं और डेटा हेरफेर के लिए इस्तेमाल करते हैं।

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. व्युत्पन्न धारावाहिक टाइपबाज़सेरियलज़र.मेमा.फील्डस का संदर्भ ले सकते हैं, ताकि आप उन्हें एक ही स्थान पर बदल सकें।
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 
संबंधित मुद्दे