2010-08-30 5 views
23

अब कुछ घंटों के लिए इसे समझने की कोशिश कर रहा है और कहीं भी नहीं मिला है।Django के ORM का उपयोग विदेशी वस्तुओं को कैसे प्राप्त किया जाता है जब उन्हें

class other(models.Model): 
    user = models.ForeignKey(User) 


others = other.objects.all() 
o = others[0] 

इस बिंदु पर ORM o.user वस्तु के लिए नहीं कहा गया है, लेकिन अगर मैं कुछ भी है कि वस्तु को छूता करते हैं, यह यह डेटाबेस से लोड करता है।

type(o.user) 

डेटाबेस से लोड का कारण बन जाएगा।

जो मैं समझना चाहता हूं वह यह है कि वे यह जादू कैसे करते हैं। पाइथोनिक पिक्सी धूल क्या है जो इसे होने का कारण बनती है। हाँ, मैंने स्रोत को देखा है, मैं फंस गया हूँ।

उत्तर

52

डीजेंगो मॉडल कक्षाओं के निर्माण को अनुकूलित करने के लिए metaclass (django.db.models.base.ModelBase) का उपयोग करता है। मॉडल पर एक वर्ग विशेषता के रूप में परिभाषित प्रत्येक ऑब्जेक्ट के लिए (user वह है जिसे हम यहां परवाह करते हैं), Django पहले यह देखने के लिए देखता है कि यह contribute_to_class विधि को परिभाषित करता है या नहीं। यदि विधि परिभाषित की जाती है, तो Django इसे कॉल करता है, जिससे ऑब्जेक्ट को मॉडल क्लास को अनुकूलित करने की इजाजत मिलती है। यदि ऑब्जेक्ट contribute_to_class को परिभाषित नहीं करता है, तो इसे setattr का उपयोग करके कक्षा में असाइन किया जाता है।

चूंकि ForeignKey एक Django मॉडल फ़ील्ड है, यह contribute_to_class को परिभाषित करता है। जब ModelBase मेटाक्लास कॉल ForeignKey.contribute_to_class पर कॉल करता है, तो ModelClass.user पर निर्दिष्ट मान django.db.models.fields.related.ReverseSingleRelatedObjectDescriptor का उदाहरण है।

ReverseSingleRelatedObjectDescriptor एक ऐसा ऑब्जेक्ट है जो क्लाइथन के descriptor protocol को लागू करता है ताकि क्लास का एक उदाहरण किसी अन्य वर्ग की विशेषता के रूप में उपयोग किया जा सके। इस मामले में, वर्णनकर्ता का उपयोग lazily load पर किया जाता है और डेटाबेस से संबंधित मॉडल उदाहरण को पहली बार एक्सेस किया जाता है।

# make a user and an instance of our model 
>>> user = User(username="example") 
>>> my_instance = MyModel(user=user) 

# user is a ReverseSingleRelatedObjectDescriptor 
>>> MyModel.user 
<django.db.models.fields.related.ReverseSingleRelatedObjectDescriptor object> 

# user hasn't been loaded, yet 
>>> my_instance._user_cache 
AttributeError: 'MyModel' object has no attribute '_user_cache' 

# ReverseSingleRelatedObjectDescriptor.__get__ loads the user 
>>> my_instance.user 
<User: example> 

# now the user is cached and won't be looked up again 
>>> my_instance._user_cache 
<User: example> 

ReverseSingleRelatedObjectDescriptor.__get__ विधि हर बार user विशेषता मॉडल उदाहरण पर पहुँचा जा सकता है कहा जाता है, लेकिन यह करने के लिए पर्याप्त स्मार्ट है केवल एक बार संबंधित वस्तु को देखने के लिए और फिर बाद में कॉल पर संचित संस्करण वापस जाएँ।

+1

+1। मुझे स्पष्टीकरण पसंद है। –

+0

धन्यवाद, यह वही है जो मैं सीखना चाहता था। – boatcoder

+0

कैश को संबंधित ऑब्जेक्ट को मजबूर करने का कोई आसान तरीका है? मैं gojogled django.db.models.fields.related.ReverseSingleRelatedObjectDescriptor और इस पोस्ट को मिला ... – yegle

1

यह कैसे समझाएगा वास्तव में Django इसके बारे में बताता है, लेकिन आप जो देख रहे हैं वह कार्रवाई में आलसी लोड हो रहा है। आलसी लोडिंग को को एक अच्छी तरह से ज्ञात डिज़ाइन पैटर्न है, जिसकी ऑब्जेक्ट की आवश्यकता होने तक ऑब्जेक्ट्स की शुरुआत शुरू हो जाती है। आपके मामले में o = others[0] या type(o.user) को निष्पादित किया गया है। यह Wikipedia article आपको प्रक्रिया में कुछ अंतर्दृष्टि दे सकता है।

+0

हाँ, मैं समझता हूं कि क्यों, मैं इस बारे में स्पष्टीकरण की तलाश कर रहा था कि उन्होंने इसे कैसे खींचा। – boatcoder

0

गुण इस व्यवहार को लागू करने के लिए उपयोग किया जा सकता है। मूल रूप से, अपने वर्ग परिभाषा एक वर्ग निम्नलिखित के समान उत्पन्न करेगा:

class other(models.Model): 
    def _get_user(self): 
     ## o.users being accessed 
     return User.objects.get(other_id=self.id) 

    def _set_user(self, v): 
     ## ... 

    user = property(_get_user, _set_user) 

जब तक आप एक 'अन्य' उदाहरण के .user का उपयोग उपयोगकर्ता पर क्वेरी प्रदर्शन नहीं किया जाएगा।

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