2016-09-23 9 views
6

डीआरएफ एपीआई के साथ मेरा डीजेगो-संचालित ऐप ठीक काम कर रहा है, लेकिन मैंने प्रदर्शन समस्याओं में भागना शुरू कर दिया है क्योंकि डेटाबेस वास्तविक डेटा के साथ पॉप्युलेट हो जाता है। मैंने Django डीबग टूलबार के साथ कुछ प्रोफाइलिंग की है और पाया है कि मेरे कई अंतराल बिंदु अपने डेटा लौटने के दौरान सैकड़ों प्रश्नों को जारी करते हैं।Django REST Framework: नेस्टेड धारावाहिकों के लिए प्रीफेचिंग सेट करना

मुझे उम्मीद थी, क्योंकि मैंने पहले डेटाबेस क्वेरी के संबंध में कुछ भी अनुकूलित नहीं किया था। अब जब मैं प्रीफेचिंग स्थापित कर रहा हूं, हालांकि, मुझे ठीक से प्रीफेच किए गए सीरिएलाइज़र डेटा का उपयोग करके परेशानी हो रही है जब उस धारावाहिक को एक अलग धारावाहिक में घोंसला दिया जाता है। मैं prefetch के विभिन्न तरीकों के बारे में सोचने के लिए एक गाइड के रूप में इस awesome post का उपयोग कर रहा हूं।

वर्तमान में, सीरिएलाइज़र ठीक से प्रीफ़ेच करता है जब मैं /api/readinggroups/ एंडपॉइंट पर हिट करता हूं। मेरा मुद्दा /api/userbookstats/ एंडपॉइंट है, जो सभी UserBookStats ऑब्जेक्ट्स देता है। संबंधित धारावाहिक, UserBookStatsSerializer, नेस्टेड ReadingGroupSerializer है।

मॉडल, serializers, और viewsets इस प्रकार हैं:

models.py

class ReadingGroup(models.model): 
    owner = models.ForeignKeyField(settings.AUTH_USER_MODEL) 
    users = models.ManyToManyField(settings.AUTH_USER_MODEL) 
    book_type = models.ForeignKeyField(BookType) 
    .... 
    <other group related fields> 

    def __str__(self): 
    return '%s group: %s' % (self.name, self.book_type) 

class UserBookStats(models.Model): 
    reading_group = models.ForeignKey(ReadingGroup) 
    user = models.ForeignKey(settings.AUTH_USER_MODEL) 
    alias = models.CharField() 

    total_books_read = models.IntegerField(default=0) 
    num_books_owned = models.IntegerField(default=0) 
    fastest_read_time = models.IntegerField(default=0) 
    average_read_time = models.IntegerField(default=0) 

serializers.py

class ReadingGroupSerializer(serializers.ModelSerializer): 
    users = UserSerializer(many = True,read_only=True) 
    owner = UserSerializer(read_only=True) 

    class Meta: 
     model = ReadingGroup 
     fields = ('url', 'id','owner', 'users') 

    @staticmethod 
    def setup_eager_loading(queryset): 
     #select_related for 'to-one' relationships 
     queryset = queryset.select_related('owner') 

     #prefetch_related for 'to-many' relationships 
     queryset = queryset.prefetch_related('users') 

     return queryset 

class UserBookStatsSerializer(serializers.HyperlinkedModelSerializer): 
    reading_group = ReadingGroupSerializer() 
    user = UserSerializer() 
    awards = AwardSerializer(source='award_set', many=True) 

    class Meta: 
     model = UserBookStats 
     fields = ('url', 'id', 'alias', 'total_books_read', 'num_books_owned', 
       'average_read_time', 'fastest_read_time', 'awards') 

    @staticmethod 
    def setup_eager_loading(queryset): 
     #select_related for 'to-one' relationships 
     queryset = queryset.select_related('user') 

     #prefetch_related for 'to-many' relationships 
     queryset = queryset.prefetch_related('awards_set') 

     #setup prefetching for nested serializers 
     groups = Prefetch('reading_group', queryset ReadingGroup.objects.prefetch_related('userbookstats_set'))   
     queryset = queryset.prefetch_related(groups) 

     return queryset 

views.py

class ReadingGroupViewset(views.ModelViewset): 

    def get_queryset(self): 
    qs = ReadingGroup.objects.all() 
    qs = self.get_serializer_class().setup_eager_loading(qs) 
    return qs 

class UserBookStatsViewset(views.ModelViewset): 

    def get_queryset(self): 
    qs = UserBookStats.objects.all() 
    qs = self.get_serializer_class().setup_eager_loading(qs) 
    return qs 

मैं ReadingGroup endpoint के लिए प्रीफेचिंग अनुकूलन किया है (मैं वास्तव में है कि अंत बिंदु here के लिए डुप्लिकेट प्रश्नों को नष्ट करने के बारे में पोस्ट), और अब मैं UserBookStats समाप्ति बिंदु पर काम कर रहा हूँ।

मुद्दा मैं आ रही है कि, के साथ मेरे वर्तमान setup_eager_loadingUserBookStatsSerializer में, यह प्रीफेचिंग ReadingGroupSerializer में उत्सुक लोड हो रहा है विधि द्वारा स्थापित उपयोग करने के लिए प्रकट नहीं होता है। मैं अभी भी Prefetch ऑब्जेक्ट के सिंटैक्स पर थोड़ा आलसी हूं - मैं उस दृष्टिकोण को आजमाने के लिए this उत्कृष्ट उत्तर से प्रेरित था।

जाहिर UserBookStatsViewset की get_queryset विधि ReadingGroup वस्तुओं के लिए setup_eager_loading फोन नहीं है, लेकिन मैं वहाँ एक ही प्रीफेचिंग पूरा करने के लिए एक रास्ता है यकीन है।

+1

क्या आप सुरुचिपूर्ण समाधान या किसी समाधान के बारे में पूछ रहे हैं? 'queryset = queryset.prefetch_related ('read_group', 'reading_group__users', 'reading_group__owner') 'ठीक काम करना चाहिए। – serg

+0

कोई भी समाधान बहुत अच्छा होगा - और वाह, यह कमाल है। यह पूरी तरह से काम करता है, इसलिए यदि आप इसे उत्तर के रूप में सबमिट करते हैं, तो मैं स्वीकार करूंगा। यह 'प्रीफेच' ऑब्जेक्ट को प्रतिस्थापित करता है, जो कि मैं एक सुरुचिपूर्ण समाधान के लिए उपयोग करने की उम्मीद कर रहा था जो कि डीक्यूपल प्रीफेचिंग की तरह होगा, लेकिन यह वास्तव में अच्छी तरह से काम करता है। धन्यवाद! – dkhaupt

उत्तर

3

prefetch_related() का समर्थन करता है डबल अंडरस्कोर वाक्य रचना का उपयोग करके आंतरिक संबंधों प्रीफ़ेचिंग:

queryset = queryset.prefetch_related('reading_group', 'reading_group__users', 'reading_group__owner') 

मुझे नहीं लगता कि Django बाकी स्वचालित रूप से सभी आवश्यक क्षेत्रों को लाते समय के लिए बॉक्स से बाहर किसी भी सुरुचिपूर्ण समाधान प्रदान करता है।