2011-01-07 23 views
6

Django modelleri ile __getattr__ kullanan kişilerden çevrimiçi örnekler gördüm, ancak ne zaman denerim, hata alıyorum. (Django 1.2.3)Neden Django modelleri ile __getattr__ kullanamıyorum?

Normal nesnelerde __getattr__ kullanırken sorun yaşıyorum.

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

İşleri gayet ... Şimdi bir Django modeli ile çalıştığınızda

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

:

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

Ve tercüman üzerinde üzerinde test:

Örneğin
>>> 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

Birisi ne olduğunu açıklayabilir mi g açık mı?


DÜZENLEME:

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... 

Ben bir yaratabilecek iken: Burada ben aslında web sitesinde kullanmak ne daha yakın olan bazı kodu örneklerde çok soyut olabilir Post sınıfının her özelliği için özellik, çok sayıda kod çoğaltmasına yol açacaktır. Dahası, bu, Post sınıfının bir özniteliğini eklediğimde veya düzenlediğimde, CuratedPost sınıfında aynı değişikliği yapmak için hatırlamak zorunda kalacağım, kod çürümesi için bir reçete gibi görünüyor.

+2

gerçekten "return self.post.name" nedir? "Return getattr (self.post, name)" olmalıdır. –

+0

Gerçekten de, bu kodun ne olması gerektiği budur – Joshmaker

cevap

0

Django, modeller ilk başlatıldığında (yani, kabuğu yükleyerek) bazı sinyalleri gönderir - __getattr numaralı çağrıların her zaman bir tam sayı döndürmesi için, kodu Django sinyallerinin olmadığı şekilde değiştirdiniz t bekliyor (ve bu yüzden, onlar kırılıyor).

Bunu yapmak istiyorsan, belki bu şekilde deneyin:

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

Bu, hasattr (self, attr) çağrıldığından beri işe yaramıyor \ _ \ _ getattr \ _ \ _ yinelemeli olarak. Bunun yerine "self_dict__" attr. –

+1

Ve aslında, bu işe yaramıyor çünkü \ _ \ _ getattr \ _ \ _ sadece attr içinde değil \ _ \ _ dict \ _ \ _ –

+1

@ 'den geçiyor: @Andrew:' __getattribute__' ile yapabileceğiniz gibi Yine de – Cameron

5

Bir __getattr__ kullanırken dikkatli olmak gerekir. Sadece bildiğin şeyi yakala ve temel sınıfın yapamadığın şeyi yapmasına izin ver.

İlk adım, bunun yerine bir mülk kullanabilir misiniz? Eğer 42 return "rastgele" özelliğini istiyorsanız o zaman bu çok daha güvenlidir:

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

İsterseniz "random_ *" o zaman bir şeyler yapmak ("random_1", ​​"random_34", vs gibi) olacak Bu gibi __getattr__ kullanmak zorunda:

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

Gönderide kullandığım örnekte, Django model nesnesini genişletirken __getattr__ özelliğinin çok basit uygulamalarının bile koptuğunu göstermesi gerekiyordu. Aslında kullandığım şeye daha yakın bir şey eklemek için orijinal gönderimi güncelledim. – Joshmaker

+2

Bunun Django ile çalışacağına inanmıyorum, çünkü models.Model '__getattr__' içermiyor, bu yüzden' super (Post, self) .__ getattr __ (...) 'bir istisna atmalı. – Cerin

+1

Denedin mi? Python bir varsayılan __getattr__ sağlar, bu yüzden 'sorun' olmamalıdır. –

İlgili konular