Django बाकी फ्रेमवर्क - ModelSerializer में कस्टम फ़ील्ड कैसे जोड़ें


89

मैंने एक बनाया ModelSerializerऔर एक कस्टम फ़ील्ड जोड़ना चाहता हूं जो मेरे मॉडल का हिस्सा नहीं है।

मुझे यहाँ अतिरिक्त फ़ील्ड जोड़ने का विवरण मिला और मैंने निम्नलिखित कोशिश की:

customField = CharField(source='my_field')

जब मैं इस क्षेत्र को जोड़ता हूं और अपने validate()कार्य को बुलाता हूं तो यह क्षेत्र attrतानाशाही का हिस्सा नहीं है । attrइसमें अतिरिक्त फ़ील्ड को छोड़कर निर्दिष्ट सभी मॉडल फ़ील्ड शामिल हैं। इसलिए मैं अपने अधिलेखित सत्यापन में इस क्षेत्र तक नहीं पहुँच सकता, क्या मैं कर सकता हूँ?

जब मैं इस फ़ील्ड को इस तरह फ़ील्ड सूची में जोड़ता हूँ:

class Meta:
    model = Account
    fields = ('myfield1', 'myfield2', 'customField')

फिर मुझे एक त्रुटि मिलती है क्योंकि customFieldमेरे मॉडल का हिस्सा नहीं है - क्या सही है क्योंकि मैं इसे इस धारावाहिक के लिए जोड़ना चाहता हूं।

क्या कोई कस्टम फ़ील्ड जोड़ने का कोई तरीका है?


क्या आप इस पर विस्तार कर सकते हैं "लेकिन जब मेरा क्षेत्र धारावाहिक में निर्दिष्ट मॉडल फ़ील्ड सूची में नहीं है तो यह मान्य () अट्रैक्शन-डिक्शनरी का हिस्सा नहीं है। मुझे यकीन नहीं है कि यह बहुत स्पष्ट है।
टॉम क्रिस्टी

इसके अलावा "यह शिकायत करता है - सही ढंग से - कि मेरे पास अपने मॉडल में एक फ़ील्ड कस्टमफिल्ड नहीं है।", क्या आप अपने देखने के अपवाद के बारे में स्पष्ट हो सकते हैं - धन्यवाद! :)
टॉम क्रिस्टी

मैंने अपनी पोस्ट अपडेट की और उम्मीद है कि अब यह स्पष्ट हो जाएगा। मैं सिर्फ यह जानना चाहता हूं कि मैं एक ऐसा क्षेत्र कैसे जोड़ सकता हूं जो मेरे मॉडल का हिस्सा नहीं है ...
रॉन


जवाबों:


63

आप सही काम कर रहे हैं, सिवाय इसके कि CharField(और अन्य टाइप किए गए क्षेत्र) लेखन योग्य क्षेत्रों के लिए हैं।

इस मामले में आप केवल एक साधारण केवल-पढ़ने के लिए फ़ील्ड चाहते हैं, इसलिए इसके बजाय बस उपयोग करें:

customField = Field(source='get_absolute_url')

4
धन्यवाद, लेकिन मैं एक लेखन क्षेत्र चाहता हूँ। मैं एक निश्चित उपयोगकर्ता टोकन पास करता हूं जो मेरे उपयोगकर्ता की पहचान करता है। लेकिन मेरे मॉडल में मेरे पास उपयोगकर्ता है और टोकन नहीं है। इसलिए मैं टोकन को पास करना चाहता हूं और इसे क्वेरी के माध्यम से उपयोगकर्ता ऑब्जेक्ट में "कन्वर्ट" करना चाहता हूं।
रॉन

अगली बात यह है कि स्रोत को एक मॉडल विशेषता को लक्षित करने की आवश्यकता है, है ना? मेरे मामले में मेरे पास इंगित करने के लिए एक विशेषता नहीं है।
रॉन

मैं टिप्पणी के उपयोगकर्ता / टोकन बिट को नहीं समझता। लेकिन यदि आप एक धारावाहिक में एक क्षेत्र को शामिल करना चाहते हैं जो एक मॉडल उदाहरण में पुनर्स्थापित करने से पहले छीन लिया जाता है, तो आप .validate()विशेषता को हटाने के लिए विधि का उपयोग कर सकते हैं । देखें: django-rest-framework.org/api-guide/serializers.html#validation आपको जो चाहिए वह करेंगे, हालाँकि मैं वास्तव में उपयोग-केस को नहीं समझता, या आप एक ऐसा लेखन क्षेत्र क्यों चाहते हैं, जो बंधा हुआ हो केवल पढ़ने के लिए संपत्ति get_absolute_url?
टॉम क्रिस्टी

भूल जाते हैं get_absolute_urlमैं सिर्फ डॉक्स से कॉपी और पेस्ट के बारे में । मैं सिर्फ एक सामान्य लेखन क्षेत्र चाहता हूं, जिसमें मैं पहुंच सकूं validate()। मैंने सिर्फ अनुमान लगाया कि मुझे इस sourceविशेषता की आवश्यकता होगी ...
रॉन

यह अधिक समझ में आता है। :) मान को मान्य करने के लिए पारित किया जाना चाहिए, इसलिए मैं दोगुना जांच करूंगा कि आप धारावाहिक को कैसे तात्कालिक बना रहे हैं, और यदि वह मूल्य वास्तव में प्रदान किया जा रहा है।
टॉम क्रिस्टी

82

वास्तव में सभी मॉडल को छूने के बिना एक समाधान है। आप का उपयोग कर सकते हैं SerializerMethodFieldजो आप अपने serializer के लिए किसी भी विधि को प्लग करने की अनुमति देते हैं।

class FooSerializer(ModelSerializer):
    foo = serializers.SerializerMethodField()

    def get_foo(self, obj):
        return "Foo id: %i" % obj.pk

6
ओपी में उल्लेख किया है इस टिप्पणी , वे एक लिखने योग्य क्षेत्र है, जो चाहते हैं SerializerMethodFieldनहीं कर रहे हैं
कृपया

14

... स्पष्टता के लिए, यदि आपके पास एक मॉडल विधि निम्नलिखित तरीके से परिभाषित है:

class MyModel(models.Model):
    ...

    def model_method(self):
        return "some_calculated_result"

आप अपने धारावाहिक को कॉल करने की विधि का परिणाम जोड़ सकते हैं जैसे:

class MyModelSerializer(serializers.ModelSerializer):
    model_method_field = serializers.CharField(source='model_method')

ps चूंकि कस्टम फ़ील्ड वास्तव में आपके मॉडल का फ़ील्ड नहीं है, आप आमतौर पर इसे केवल पढ़ने के लिए बनाना चाहते हैं, जैसे:

class Meta:
    model = MyModel
    read_only_fields = (
        'model_method_field',
        )

3
क्या होगा अगर मैं चाहता हूं कि यह योग्य हो?
Csaba टोथ

1
@Csaba: तुम बस लिखने कस्टम बचाने और अतिरिक्त सामग्री के लिए हटाए जाने के हुक करने की आवश्यकता होगी: "तरीके" के अंतर्गत देखें "सहेजें और विलोपन हुक" ( यहाँ ) आप लिखने कस्टम की आवश्यकता होगी perform_create(self, serializer), perform_update(self, serializer), perform_destroy(self, instance)
लिंडसन

13

यहाँ आपके प्रश्न का उत्तर है। आपको अपने मॉडल में जोड़ना चाहिए खाता:

@property
def my_field(self):
    return None

अब आप उपयोग कर सकते हैं:

customField = CharField(source='my_field')

स्रोत: https://stackoverflow.com/a/18396622/3220916


6
मैंने इस दृष्टिकोण का उपयोग किया है जब यह समझ में आता है, लेकिन उन चीजों के लिए मॉडल में अतिरिक्त कोड जोड़ना महान नहीं है जो केवल विशिष्ट एपीआई कॉल के लिए वास्तव में उपयोग किए जाते हैं।
एंडी बेकर

1
आप के लिए एक प्रॉक्सी मॉडल लिख सकते हैं
ashwoods

10

दिखाने के लिए self.author.full_name, मुझे एक त्रुटि मिली Field। इसके साथ काम किया ReadOnlyField:

class CommentSerializer(serializers.HyperlinkedModelSerializer):
    author_name = ReadOnlyField(source="author.full_name")
    class Meta:
        model = Comment
        fields = ('url', 'content', 'author_name', 'author')

6

Django रेस्ट फ्रेमवर्क के अंतिम संस्करण के साथ, आपको अपने मॉडल में उस फ़ील्ड के नाम के साथ एक विधि बनाने की आवश्यकता है जिसे आप जोड़ना चाहते हैं।

class Foo(models.Model):
    . . .
    def foo(self):
        return 'stuff'
    . . .

class FooSerializer(ModelSerializer):
    foo = serializers.ReadOnlyField()

    class Meta:
        model = Foo
        fields = ('foo',)

3

मैं एक मॉडल धारावाहिक के लिए एक लिखने योग्य कस्टम क्षेत्र को जोड़ने के लिए एक समाधान की तलाश कर रहा था। मैंने इसे पाया, जो इस प्रश्न के उत्तर में शामिल नहीं है।

ऐसा लगता है कि आपको वास्तव में अपना खुद का सरल सीरियल लिखने की ज़रूरत है।

class PassThroughSerializer(serializers.Field):
    def to_representation(self, instance):
        # This function is for the direction: Instance -> Dict
        # If you only need this, use a ReadOnlyField, or SerializerField
        return None

    def to_internal_value(self, data):
        # This function is for the direction: Dict -> Instance
        # Here you can manipulate the data if you need to.
        return data

अब आप इस Serializer का उपयोग करके किसी ModelSerializer में कस्टम फ़ील्ड जोड़ सकते हैं

class MyModelSerializer(serializers.ModelSerializer)
    my_custom_field = PassThroughSerializer()

    def create(self, validated_data):
        # now the key 'my_custom_field' is available in validated_data
        ...
        return instance

यह भी काम करता है, अगर मॉडल में MyModelवास्तव में एक संपत्ति है, my_custom_fieldलेकिन आप इसके सत्यापनकर्ताओं को अनदेखा करना चाहते हैं।


तो यह काम नहीं करता है अगर my_custom_field MyModel की संपत्ति सही नहीं है? मुझे त्रुटि मिली सीरियल सीरियल फ़ील्ड को गलत तरीके से नाम दिया जा सकता है और MyModelउदाहरण पर किसी भी विशेषता या कुंजी से मेल नहीं खाता है ।
संदीप बालगोपाल

2

यहां सभी उत्तरों को पढ़ने के बाद मेरा निष्कर्ष यह है कि यह सफाई से करना असंभव है। आपको गंदा खेलना होगा और कुछ करना होगा जैसे कि राइट_ऑनली फ़ील्ड बनाना और फिर validateऔर to_representationतरीकों को ओवरराइड करना । इसी से मेरा काम बना है:

class FooSerializer(ModelSerializer):

    foo = CharField(write_only=True)

    class Meta:
        model = Foo
        fields = ["foo", ...]

    def validate(self, data):
        foo = data.pop("foo", None)
        # Do what you want with your value
        return super().validate(data)

    def to_representation(self, instance):
        data = super().to_representation(instance)
        data["foo"] = whatever_you_want
        return data
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.