2011-01-07 11 views
6

मैंने Django मॉडल के साथ __getattr__ का उपयोग कर लोगों के ऑनलाइन उदाहरण देखे हैं, लेकिन जब भी मैं कोशिश करता हूं तो मुझे त्रुटियां मिलती हैं। (Django 1.2.3)मैं Django मॉडल के साथ __getattr__ का उपयोग क्यों नहीं कर सकता?

मुझे कोई समस्या नहीं है जब मैं सामान्य वस्तुओं पर __getattr__ का उपयोग कर रहा हूं।

class Post(object): 
    def __getattr__(self, name): 
     return 42 

वर्क्स ठीक ...

>>> from blog.models import Post 
>>> p = Post() 
>>> p.random 
42 

अब जब मैं एक Django मॉडल के साथ प्रयास करें:

from django.db import models 
class Post(models.Model): 
    def __getattr__(self, name): 
     return 42 

और व्याख्याता का उस पर परीक्षण:

उदाहरण के लिए
>>> from blog.models import Post 
>>> p = Post() 
ERROR: An unexpected error occurred while tokenizing input The 

following traceback may be corrupted or invalid The error message is: ('EOF in multi-line statement', (6, 0))

--------------------------------------------------------------------------- TypeError
Traceback (most recent call last)

/Users/josh/project/ in()

/Users/josh/project/lib/python2.6/site-packages/django/db/models/base.pyc in init(self, *args, **kwargs) 338 if kwargs: 339 raise TypeError("'%s' is an invalid keyword argument for this function" % kwargs.keys()[0]) --> 340 signals.post_init.send(sender=self.class, instance=self) 341 342 def repr(self):

/Users/josh/project/lib/python2.6/site-packages/django/dispatch/dispatcher.pyc in send(self, sender, **named) 160 161 for receiver in self._live_receivers(_make_id(sender)): --> 162 response = receiver(signal=self, sender=sender, **named) 163 responses.append((receiver, response)) 164 return responses

/Users/josh/project/python2.6/site-packages/photologue/models.pyc in add_methods(sender, instance, signal, *args, **kwargs) 728 """ 729 if hasattr(instance, 'add_accessor_methods'): --> 730 instance.add_accessor_methods() 731 732 # connect the add_accessor_methods function to the post_init signal

TypeError: 'int' object is not callable

कोई बता सकता है कि क्या चल रहा है जी पर?


संपादित करें: मैं उदाहरण में भी सार हो सकता है, यहाँ कुछ कोड है कि क्या मैं वास्तव में वेबसाइट पर प्रयोग करेंगे के करीब है:

class Post(models.Model): 
    title = models.CharField(max_length=255) 
    slug = models.SlugField() 
    date_published = models.DateTimeField() 
    content = RichTextField('Content', blank=True, null=True) 
    # Etc... 

Class CuratedPost(models.Model): 
    post = models.ForeignKey('Post') 
    position = models.PositiveSmallIntegerField() 

    def __getattr__(self, name): 
     ''' If the user tries to access a property of the CuratedPost, return the property of the Post instead... ''' 
     return self.post.name 

    # Etc... 

जब मैं एक बना सकते हैं पोस्ट क्लास की प्रत्येक विशेषता के लिए संपत्ति, जो बहुत सारे कोड डुप्लिकेशंस का कारण बनती है। और भी, इसका मतलब यह होगा कि जब भी मैं पोस्ट क्लास की विशेषता जोड़ता हूं या संपादित करता हूं तो मुझे क्यूरेटेड पोस्ट क्लास में एक ही बदलाव करना याद रखना होगा, जो कोड रोट के लिए नुस्खा जैसा लगता है।

+2

कि वास्तव में "वापसी self.post.name" क्या है? यह "वापसी getattr (self.post, name)" –

+0

होना चाहिए, वास्तव में, कोड – Joshmaker

उत्तर

0

Django कुछ संकेतों को भेजता है जब मॉडल को पहली बार प्रारंभ किया जाता है (यानी, खोल को लोड करके) - इसे बनाकर __getattr पर कॉल करने से हमेशा एक पूर्णांक वापस आ जाता है, आपने कोड को इस तरह से संशोधित किया है कि Django संकेतों को ' टी उम्मीद कर रहा है (और इसलिए, वे तोड़ रहे हैं)।

यदि आप ऐसा करना चाहते हैं, तो हो सकता है कि यह इस तरह का प्रयास करें:

def __getattr__(self, attr): 
    if hasattr(self, attr): 
    return super(MyModel, self).__getattr__(attr) 
    return 42 
+0

होना चाहिए यह हैटैर (स्वयं, attr) कॉलिंग \ _ \ _ getattr \ _ \ _ को फिर से कॉल करने के बाद समाप्त नहीं होता है। आप इसके बजाय "self.__ dict__" में attr चाहते हैं। –

+1

और असल में, यह तब तक काम नहीं करेगा जब \ _ \ _ getattr \ _ \ _ केवल कॉल किया जाता है अगर attr \ _ \ _ dict \ _ \ _ –

+1

@Andrew में नहीं है: लगता है जैसे आप '__getattribute__' के साथ ऐसा कर सकते हैं, हालांकि – Cameron

5

एक __getattr__ का उपयोग कर सावधान रहना चाहिए। केवल आप जो जानते हैं उसे रोकें, और बेस क्लास को जो भी आप नहीं करते हैं उसे संभालें।

पहला कदम है, क्या आप इसके बजाय संपत्ति का उपयोग कर सकते हैं? आप एक "यादृच्छिक" विशेषता जो लौट 42 चाहते हैं तो इस ज्यादा सुरक्षित है:

class Post(...): 
    @property 
    def random(self): 
    return 42 

यदि आप चाहते हैं "random_ *" कुछ तो ऐसा करने के लिए ("random_1", ​​"random_34", आदि) की तरह आप करेंगे इस तरह __getattr__ उपयोग करने के लिए:

class Post(...): 
    def __getattr__(self, name): 
    if name.startswith("random_"): 
     return name[7:] 
    return super(Post, self).__getattr__(name) 
+0

मेरे पोस्ट में उपयोग किए जाने वाले उदाहरण को यह दिखाना था कि जब मैं Django मॉडल ऑब्जेक्ट का विस्तार करता हूं तो __getattr__ प्रॉपर्टी ब्रेक के बहुत ही सरल अनुप्रयोग भी होते हैं। मैंने अपनी मूल पोस्ट को अपडेट किया है जिसमें मैं वास्तव में उपयोग करने के करीब कुछ शामिल कर सकता हूं। – Joshmaker

+2

मुझे विश्वास नहीं है कि यह Django के साथ काम करेगा, क्योंकि मॉडल। मॉडल में '__getattr__' नहीं है, इसलिए आपका' सुपर (पोस्ट, स्वयं) .__ getattr __ (...) 'को अपवाद फेंकना चाहिए। – Cerin

+1

क्या आपने इसे आजमाया है? पायथन एक डिफ़ॉल्ट __getattr__ प्रदान करता है, इसलिए यह एक समस्या नहीं होनी चाहिए। –

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