2011-01-02 10 views
24

Django में, अगर मेरे पास मॉडल श्रेणी है, उदा।Django में, क्या आप क्वेरीसेट में कोई विधि जोड़ सकते हैं?

from django.db import models 

class Transaction(models.Model): 
    ... 

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

class TransactionManager(models.Manager): 

    def reasonably_complex_filter(self): 
     return self.get_query_set().filter(...) 


class Transaction(models.Model): 
    objects = TransactionManager() 

और फिर मैं कर सकते हैं:

>>> Transaction.objects.reasonably_complex_filter() 

वहाँ किसी भी तरह से मुझे लगता है कि एक प्रश्न मॉडल से सेट के अंत तक श्रृंखलित किया जा सकता है एक कस्टम विधि जोड़ सकते हैं है?

अर्थात इस तरह से है कि मैं ऐसा कर सकते हैं में कस्टम विधि जोड़ें:

>>> Transaction.objects.filter(...).reasonably_complex_filter() 

उत्तर

5

आप QuerySet जो आप अंततः के साथ खत्म करने के तरीकों जोड़ने की जरूरत है। तो आपको QuerySet सबक्लास बनाने और उपयोग करने की आवश्यकता है जिसमें आप जिस कार्यक्षमता को परिभाषित करते हैं, उसे परिभाषित करने के तरीके हैं।

मैं इस ट्यूटोरियल जो इसे और कारणों कैसे करना है तुम क्यों करना चाह सकते हैं बताते हैं पाया:

http://adam.gomaa.us/blog/2009/feb/16/subclassing-django-querysets/index.html

+0

राइट, गॉचा। क्या आप जानते हैं कि उस ब्लॉग पोस्ट में सुझाई गई विधि विश्वसनीय तरीके से काम करती है या नहीं? टिप्पणियों से पता चलता है कि '__getattr__' दृष्टिकोण में कुछ समस्याएं हैं। –

+0

मैंने इस कोड को खुद अभ्यास में नहीं रखा है, लेकिन मैंने इसी तरह से पहले डीजेगो परियोजनाओं में विश्वसनीय रूप से '__getattr__' का उपयोग किया है। –

+1

आलेख काफी पुराना है, लेकिन बिंदु यह है कि आपको कुछ तरीकों से 'क्वेरीजेट' ऑब्जेक्ट में अपनी विधियों को संलग्न करने की आवश्यकता है। –

3

आप एक कस्टम क्वेरीसमूह वापस जाने के लिए get_query_set() विधि को संशोधित कर सकता है, तरीकों की आवश्यकता जोड़ने। आपके मामले में, आप का प्रयोग करेंगे:

class TransactionManager(models.Manager): 
    def get_query_set(self): 
     return TransactionQuerySet(self.model) 

class TransactionQuerySet(models.query.QuerySet): 
    def reasonably_complex_filter(self): 
     return self.filter(...) 

रहा Transaction मॉडल में TransactionQuerySet उपवर्गीकरण, या संबंधित Manager में उदाहरण देखा है, लेकिन है कि पूरी तरह से आप पर निर्भर है।

संपादित: मैं तथ्य यह है कि TransactionManager और इसलिए Transaction.objects.reasonably_complex_filter() को objects पहला संदर्भ मेरी कार्यान्वयन में संभव नहीं है अनदेखा कर दिया लगते हैं। इसे तीन तरीकों से तय किया जा सकता है:

  • प्रबंधक और क्वेरीरीसेट दोनों में reasonably_complex_filter लागू करें;
  • Transaction.objects.all().reasonably_complex_filter() का उपयोग करें जब यह एकमात्र फ़िल्टर आवश्यक हो;
  • मार्कस व्हाइब्रो के समाधान के लिए उत्तर का संदर्भ लें जो QuerySet और Manager दोनों में कोड डुप्लिकेशन के बिना विधि को लागू करेगा।

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

0

मैं वास्तव में एक और विधि के साथ जा रहा था।यह पता चला मैं केवल filter कॉल अपने कस्टम विधि के अंत पर श्रृंखला की जरूरत थी, इसलिए मैं अपने विधि में संशोधन मनमाना कीवर्ड तर्क ले, और मेरे यथोचित जटिल क्वेरी के छोर पर एक filter() कॉल करने के उन के माध्यम से पारित करने के लिए:

class TransactionManager(models.Manager): 

    def reasonably_complex_filter(self, **kwargs): 
     return self.get_query_set().filter(...).filter(**kwargs) 

मेरे उद्देश्यों के लिए ठीक काम करने लगता है, और QuerySet subclassing से थोड़ा सा सरल है।

14

यह एक पूर्ण समाधान है जो Django 1.3 में काम करने के लिए जाना जाता है, Zach Smith और बेन की सौजन्य।

class Entry(models.Model): 
    objects = EntryManager() # don't forget this 

    is_public = models.BooleanField() 
    owner = models.ForeignKey(User) 


class EntryManager(models.Manager): 
    '''Use this class to define methods just on Entry.objects.''' 
    def get_query_set(self): 
     return EntryQuerySet(self.model) 

    def __getattr__(self, name, *args): 
     if name.startswith("_"): 
      raise AttributeError 
     return getattr(self.get_query_set(), name, *args) 

    def get_stats(self): 
     '''A sample custom Manager method.''' 
     return { 'public_count': self.get_query_set().public().count() } 


class EntryQuerySet(models.query.QuerySet): 
    '''Use this class to define methods on queryset itself.''' 
    def public(self): 
     return self.filter(is_public=True) 

    def by(self, owner): 
     return self.filter(owner=owner) 


stats = Entry.objects.get_stats()  
my_entries = Entry.objects.by(request.user).public() 

नोट:get_query_set() विधि is now deprecated in Django 1.6; इस मामले में get_queryset() का उपयोग किया जाना चाहिए।

29

Django 1.7 के रूप में, क्षमता to use a query set as a manager जोड़ा गया है:

class PersonQuerySet(models.QuerySet): 
    def authors(self): 
     return self.filter(role='A') 

    def editors(self): 
     return self.filter(role='E') 

class Person(models.Model): 
    first_name = models.CharField(max_length=50) 
    last_name = models.CharField(max_length=50) 
    role = models.CharField(max_length=1, choices=(('A', _('Author')), 
                ('E', _('Editor')))) 
    people = PersonQuerySet.as_manager() 

परिणामस्वरूप निम्नलिखित:

Person.people.authors(last_name='Dahl') 

इसके अलावा, custom lookups को जोड़ने की क्षमता भी जोड़ा गया।

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