2013-10-19 11 views
12

पर उपयोगकर्ता विशिष्ट फ़ील्ड जोड़ें, मैं एक धारावाहिक में एक फ़ील्ड जोड़ना चाहता हूं जिसमें उपयोगकर्ता को वर्तमान अनुरोध करने के लिए विशिष्ट जानकारी शामिल है (मैं इसके लिए एक अलग अंतराल बनाना नहीं चाहता)। यहाँ है जिस तरह से मैंने किया:Django REST Framework serializer

viewset:

class ArticleViewSet(viewsets.ModelViewSet): 
    queryset = Article.objects.all() 
    serializer_class = ArticleSerializer 
    filter_class = ArticleFilterSet 

    def prefetch_likes(self, ids): 
     self.current_user_likes = dict([(like.article_id, like.pk) for like in Like.objects.filter(user=self.request.user, article_id__in=ids)]) 

    def get_object(self, queryset=None): 
     article = super(ArticleViewSet, self).get_object(queryset) 
     self.prefetch_likes([article.pk]) 
     return article 

    def paginate_queryset(self, queryset, page_size=None): 
     page = super(ArticleViewSet, self).paginate_queryset(queryset, page_size) 
     if page is None: 
      return None 

     ids = [article.pk for article in page.object_list] 
     self.prefetch_likes(ids) 

     return page 

serializer:

class ArticleSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Article 

    def to_native(self, obj): 
     ret = super(ArticleSerializer, self).to_native(obj) 

     if obj: 
      view = self.context['view'] 
      ret['has_liked'] = False 
      if hasattr(view, 'current_user_liked'): 
       ret['has_liked'] = obj.pk in view.current_user_liked 

     return ret 

वहाँ पसंद आया लेख के प्रीफेचिंग इंजेक्षन लिए एक बेहतर जगह है, या सामान्य रूप से ऐसा करने का एक अच्छा तरीका?

उत्तर

8

मैं Like मॉडल ऑब्जेक्ट पर जितना संभव हो उतना प्रयास करने और इसे कस्टम सीरियलाइज़र फ़ील्ड में बंग करने के इच्छुक हूं।

serializer क्षेत्रों में आप context पैरामीटर है कि वे अपने माता पिता serializer से वारिस के माध्यम से request पहुँच सकते हैं।

तो तुम कुछ इस तरह कर सकते हैं:

class LikedByUserField(Field): 
    def to_native(self, article): 
     request = self.context.get('request', None) 
     return Like.user_likes_article(request.user, article) 

user_likes_article वर्ग विधि फिर अपने प्रीफेचिंग (और संचय) तर्क संपुटित सकता है।

मुझे उम्मीद है कि इससे मदद मिलती है।

+0

मैं कस्टम फ़ील्ड पसंद है, लेकिन 'user_likes_article' कैशिंग/प्रीफेचिंग के रास्ते में ज्यादा नहीं कर पा रहा हो सकता है अगर तुम सब यह एक लेख पार जाते हैं। 'Get_queryset' के अंदर प्रीफेचिंग करने का कारण यह है कि अनुरोध के लिए प्रासंगिक सभी आलेख आईडी वहां ज्ञात हैं। क्या क्वेरीसेट किसी भी तरह से धारावाहिक क्षेत्र में उपलब्ध है? –

+0

मुझे लगता है कि आप user_likes (या ऐसे) के एक (कैश किए गए) संग्रह से आलेख चुनने के लिए एकल आलेख पैरामीटर का उपयोग करेंगे, आपकी क्वेरीसेट केवल Article.objects.all() सही है? वहाँ कुछ भी अनुरोध अनुरोध नहीं है लेकिन वास्तव में आप user_likes_article को कैसे लागू करेंगे (निश्चित रूप से) आप जो भी करने की कोशिश कर रहे हैं उस पर निर्भर करते हैं। –

+0

मुझे एहसास हुआ कि मेरे मूल प्रश्न में एक गंभीर बग था; यह सभी सम्मान क्वेरीसेट फ़िल्टरिंग या अंकन नहीं था। मैंने इसे अभी संशोधित किया है, और मुझे लगता है कि यह थोड़ा और समझ में आता है। आप देख सकते हैं कि कैसे प्रीफेचिंग अनुरोध (फ़िल्टरिंग और पेजिनेशन) के साथ कसकर जोड़ती है और मैं इसे आसानी से पसंद मॉडल में नहीं ले जा सकता हूं। –

26

आप के साथ SerializerMethodField

उदाहरण यह कर सकते हैं:

class PostSerializer(serializers.ModelSerializer): 
    fav = serializers.SerializerMethodField('likedByUser') 

    def likedByUser(self, obj): 
     request = self.context.get('request', None) 
     if request is not None: 
      try: 
       liked=Favorite.objects.filter(user=request.user, post=obj.id).count() 
       return liked == 1 
      except Favorite.DoesNotExist: 
       return False 
     return "error" 

    class Meta: 
     model = Post 

तो आप इस तरह देखने से serializer बुलाना चाहिए:

class PostView(APIVIEW): 
    def get(self,request): 
     serializers = PostSerializer(PostObjects,context={'request':request}) 
+0

फ़िल्टर का उपयोग करते समय आपको 'को छोड़कर' प्रयास करने की आवश्यकता नहीं है, यदि क्वेरी खाली है, तो यह एक खाली क्वेरी नहीं देता है, बस एक खाली क्वेरी देता है। और 'गिनती()' के बजाय आप 'मौजूदा() 'सीधे उपयोग कर सकते हैं। – Sassan

0

Django Documentation - SerializerMethodField के अनुसार, मैं करने के लिए किया था थोड़ा सा तेजी से 2share कोड बदलें।

class ResourceSerializer(serializers.ModelSerializer): 
    liked_by_user = serializers.SerializerMethodField() 

    def get_liked_by_user(self, obj : Resource): 
     request = self.context.get('request') 
     return request is not None and obj.likes.filter(user=request.user).exists()