2013-08-19 6 views
13

डैंजो रीस्ट फ्रेमवर्क में, एक फ्लैट, रीड-राइट सीरियलाइज़र प्रतिनिधित्व बनाने में क्या शामिल है? दस्तावेज़ों में 'फ्लैट प्रतिनिधित्व' (अनुभाग http://django-rest-framework.org/api-guide/serializers.html#dealing-with-nested-objects का अंत) का संदर्भ है, लेकिन RelatedField सबक्लास का उपयोग करने के लिए सुझावों के अलावा उदाहरण या कुछ भी प्रदान न करें।डीजेगो आरईएसटी फ्रेमवर्क फ्लैट, रीड-राइट सीरियलाइज़र

उदाहरण के लिए, User और UserProfile संबंधों का एक फ्लैट प्रतिनिधित्व कैसे प्रदान करें?

# Model 
class UserProfile(models.Model): 
    user = models.OneToOneField(User) 
    favourite_number = models.IntegerField() 

# Serializer 
class UserProfileSerializer(serializers.ModelSerializer): 
    email = serialisers.EmailField(source='user.email') 
    class Meta: 
     model = UserProfile 
     fields = ['id', 'favourite_number', 'email',] 

ऊपर UserProfileSerializeremail क्षेत्र के लिए लिख की अनुमति नहीं है, लेकिन मुझे आशा है कि यह पर्याप्त रूप से अच्छी तरह से इरादा व्यक्त करता है। तो, UserProfileSerializer पर लिखने योग्य email विशेषता को अनुमति देने के लिए 'फ्लैट' रीड-राइट सीरियलाइज़र का निर्माण कैसे किया जाना चाहिए? क्या मॉडलसेरियलाइज़र को उप-वर्गीकरण करते समय ऐसा करना संभव है?

धन्यवाद।

उत्तर

6

डीजेगो आरईएसटी ढांचे (डीआरएफ) स्रोत को देखते हुए मैंने इस विचार पर निपटाया कि एक डीआरएफ धारावाहिक दृढ़ता से उद्देश्यों के लिए एक मॉडल के साथ दृढ़ता से बंधे हैं। Field के source परम serializing उद्देश्यों के लिए यह कम बनाते हैं।

मन में है कि, और साथ

सत्यापन encapsulating के रूप में serializers देखने और व्यवहार को बचाने (उनके (संयुक्त राष्ट्र के अलावा) serializing व्यवहार) मैं दो serializers इस्तेमाल किया: उपयोगकर्ता और UserProfile मॉडलों में से प्रत्येक के लिए एक:

class UserSerializer(serializer.ModelSerializer): 
    class Meta: 
     model = User 
     fields = ['email',] 

class UserProfileSerializer(serializer.ModelSerializer): 
    email = serializers.EmailField(source='user.email') 
    class Meta: 
     model = UserProfile 
     fields = ['id', 'favourite_number', 'email',] 

sourceEmailField पर पैरामीटर क्रमशः क्रमबद्धता केस को संभालता है (उदाहरण के लिए जब GET अनुरोधों की सेवा करते हैं)। unserializing (जैसे जब PUT अनुरोध serivicing) के लिए यह मान्यता के संयोजन ध्यान में रखते हुए एक छोटे से काम करते हैं, और दो serializers के व्यवहार को बचाने के लिए आवश्यक है:

class UserProfileRetrieveUpdate(generics.GenericAPIView): 
    def get(self, request, *args, **kwargs): 
     # Only UserProfileSerializer is required to serialize data since 
     # email is populated by the 'source' param on EmailField. 
     serializer = UserProfileSerializer(
       instance=request.user.get_profile()) 
     return Response(serializer.data) 

    def put(self, request, *args, **kwargs): 
     # Both UserProfileSerializer and UserProfileSerializer are required 
     # in order to validate and save data on their associated models. 
     user_profile_serializer = UserProfileSerializer(
       instance=request.user.get_profile(), 
       data=request.DATA) 
     user_serializer = UserSerializer(
       instance=request.user, 
       data=request.DATA) 
     if user_profile_serializer.is_valid() and user_serializer.is_valid(): 
      user_profile_serializer.save() 
      user_serializer.save() 
      return Response(
        user_profile_serializer.data, status=status.HTTP_200_OK) 
     # Combine errors from both serializers. 
     errors = dict() 
     errors.update(user_profile_serializer.errors) 
     errors.update(user_serializer.errors) 
     return Response(errors, status=status.HTTP_400_BAD_REQUEST) 
+0

पॉल, आपका अनुरोध है। यहां एक एकल JSON नेस्टेड सरणी है, या क्या आपके पास POST अनुरोध में प्रत्येक मॉडल के लिए एक है? (मैं कुछ इसी तरह हासिल करने की कोशिश कर रहा हूं) – jvc26

+0

@ jvc26, ऊपर मेरा उदाहरण 'अनुरोध। डेटा' में एक रूट रूट JSON ऑब्जेक्ट का उपयोग करेगा। 'request.DATA' इस तरह कुछ दिखाई देगा: ' {'id': '1', 'favourite_number': '2', 'ईमेल': '[email protected]'} ' जहां तक ​​ग्राहक है चिंतित है कि JSON ऑब्जेक्ट एक मॉडल उदाहरण का प्रतिनिधित्व करता है, और उसे दो मॉडल ('उपयोगकर्ता' और 'UserProfile') का कोई ज्ञान नहीं होगा, जो वास्तव में सर्वर पर टूट जाता है। 'UserSerializer' और 'UserProfileSerializer' का उपयोग अनुरोध से सामग्री निकालने, सत्यापित करने और सहेजने के लिए किया जाता है। उनके संबंधित मॉडल के लिए डेटा। –

2

पहला: नेस्टेड लिखने का बेहतर प्रबंधन इस तरह से है।

दूसरा: दोनों PrimaryKeyRelatedField और SlugRelatedField की Serializer Relations docs कहते हैं कि "डिफ़ॉल्ट रूप से इस क्षेत्र है पढ़ने-लिखने की ..." - इसलिए यदि आपके ईमेल क्षेत्र अद्वितीय था (यह क्या है?) यह आप SlugRelatedField इस्तेमाल कर सकते हैं हो सकता है और हो सकता है यह सिर्फ काम करेगा - मैंने अभी तक यह कोशिश नहीं की है (हालांकि)।

तीसरा: इसके बजाय मैंने एक सादा Field सबक्लास का उपयोग किया है जो पूरे ऑब्जेक्ट को स्वीकार करने के लिए source="*" technique का उपयोग करता है। वहां से मैं मैन्युअल रूप से to_native में संबंधित फ़ील्ड खींचता हूं और उसे वापस करता हूं - यह केवल पढ़ने के लिए है। लिखने के लिए मैंने अनुरोध की जांच की है। post_save में डेटा और संबंधित ऑब्जेक्ट को अपडेट किया गया - यह स्वचालित नहीं है लेकिन यह काम करता है।

तो, चौथा: क्या आप पहले से ही मिल गया है को देखते हुए, मेरी दृष्टिकोण (ऊपर) के रूप में केवल पढ़ने के लिए और उसके बाद post_save को लागू करने के लिए एक email मूल्य के लिए जाँच करें और तदनुसार अद्यतन प्रदर्शन करने के लिए अपने email क्षेत्र अंकन के बराबर है।

+0

धन्यवाद, @ कार्टन-गिब्सन। (1) मैं नेस्टेड प्रस्तुतियों पर आसान लिखने की उम्मीद करूँगा। (2) उदाहरण के लिए मेरा उदाहरण सरलीकृत है, लेकिन आपका सुझाव दिलचस्प है। (3 और 4) कुछ post_save() झुकाव मेरे साथ हुआ था, और मैंने इसे अन्य परिस्थितियों में उपयोग किया है, लेकिन दो धारावाहिकों का उपयोग (मेरा स्वयं का जवाब) क्लीनर और अधिक मजबूत लगता है। –

0

इस हालांकि सख्ती से सवाल का जवाब नहीं है - मुझे लगता है कि यह आपकी ज़रूरत को हल करेगा। यह समस्या डीआरएफ के साथ किसी मुद्दे की तुलना में एक इकाई का प्रतिनिधित्व करने के लिए दो मॉडल के विभाजन में अधिक हो सकती है।

Django 1 के बाद से।5, आप एक कस्टम उपयोगकर्ता कर सकते हैं अगर सभी आप चाहते हैं कुछ विधि और अतिरिक्त क्षेत्रों है, लेकिन इसके अलावा आप Django उपयोगकर्ता से खुश हैं, तो तुम सब करने की जरूरत है:

class MyUser(AbstractBaseUser): favourite_number = models.IntegerField()

और में सेटिंग्स: AUTH_USER_MODEL = 'myapp.myuser'

(और निश्चित रूप से एक डीबी-माइग्रेशन, जिसे आपकी मौजूदा उपयोगकर्ता तालिका को इंगित करने के लिए db_table विकल्प का उपयोग करके काफी सरल बनाया जा सकता है और बस वहां नए कॉलम जोड़ें)।

उसके बाद, आपके पास सामान्य मामला है जो डीआरएफ उत्कृष्ट होता है।

संबंधित मुद्दे