2010-08-12 3 views
1

У меня есть Джанго модель, как это:Resuable члены модели в Джанго

class Something(models.Model):  
    title = models.CharField(max_length=200, default=u'') 
    text = models.CharField(max_length=250, default=u'', blank=True) 
    photo = models.ImageField(upload_to=u'something') 
    def photo_thumb(self): 
     if self.photo: 
      return u'<img src="%s" />' % (settings.MEDIA_URL + '/thumbs/?h=64&w=80&c=50x0&p=' + self.photo.name) 
     else: 
      return u'(no photo)' 
    photo_thumb.short_description = u'Photo' 
    photo_thumb.allow_tags = True 
    photo_thumb.admin_order_field = 'photo' 
    def __unicode__(self): 
     return self.title; 

class SomethingElse(models.Model):  
    name = models.CharField(max_length=200, default=u'') 
    foo = models.CharField(max_length=250, default=u'', blank=True) 
    photo = models.ImageField(upload_to=u'something_else') 
    def photo_thumb(self): 
     if self.photo: 
      return u'<img src="%s" />' % (settings.MEDIA_URL + '/thumbs/?h=64&w=80&c=50x0&p=' + self.photo.name) 
     else: 
      return u'(no photo)' 
    photo_thumb.short_description = u'Photo' 
    photo_thumb.allow_tags = True 
    photo_thumb.admin_order_field = 'photo' 
    def __unicode__(self): 
     return self.title; 

Я чувствую, что это нарушает СУХОЙ, по понятным причинам. Мой вопрос, могу ли я придерживаться этого где-то еще:

# ... 
    def photo_thumb(self): 
     if self.photo: 
      return u'<img src="%s" />' % (settings.MEDIA_URL + '/thumbs/?h=64&w=80&c=50x0&p=' + self.photo.name) 
     else: 
      return u'(no photo)' 
    photo_thumb.short_description = u'Photo' 
    photo_thumb.allow_tags = True 
    photo_thumb.admin_order_field = 'photo' 
    # ... 

А затем включить его в соответствующих классах моделей с одной строки кода? Или может ли photo_thumb динамически добавляться в соответствующие классы? Я пробовал классическое и паразитическое наследование, но я, возможно, не делаю этого правильно ... Я новичок в Django и довольно новичок в python. Любая помощь приветствуется.

ответ

1

Другим решением может быть создание подкласса ImageField и переопределение метода contribute_to_class:

class ImageWithThumbnailField(ImageField): 
    def contribute_to_class(self, cls, name): 
     super(ImageWithThumbnailField, self).contribute_to_class(cls, name) 


     def photo_thumb(self): 
      photo = getattr(self, name, None) 
      if photo: 
       return u'<img src="%s" />' % (settings.MEDIA_URL + '/thumbs/?h=64&w=80&c=50x0&p=' + photo.name) 
      else: 
       return u'(no photo)' 
     photo_thumb.short_description = u'Photo' 
     photo_thumb.allow_tags = True 
     photo_thumb.admin_order_field = 'photo' 

     setattr(cls, 'photo_thumb', photo_thumb); 

Я думаю, что это лучше, потому что при вызове метода photo_thumb вы ожидаете существования self.photo, который не гарантируется, если вы используете другое решение, использующее абстрактную модель.

EDIT: Обратите внимание, что вы можете использовать getattr(self, name) для динамического доступа к полю. Так что да, мы гарантируем, что у нас есть поле .

+0

, но нет гарантии, что у 'ImageField' есть свойство' photo', есть ли? Это интересное решение, хотя, спасибо. –

+0

@no, вы можете использовать 'getattr' для получения поля, которое вы объявляете, и вам не нужно называть поле' photo' всюду. – satoru

+0

Это добавит метод миниатюр в поле фото, а не к самому классу модели, правильно? Разве метод не должен принадлежать классу модели, чтобы он отображался в списке администраторов? –

1

Уверенный, что вы можете повторно использовать код. Просто оцените его в базовом классе и сделайте оба класса наследуемыми от этого базового класса. Это должно работать нормально. Просто не забывайте, что базовый класс либо должен наследовать от моделей. Моделя себя (тогда я бы предложил making it abstract), или вы можете поместить код многократного использования в mixin; это означает, что ваши оба класса будут наследоваться от обеих моделей. Модель и новый базовый класс mixin.

3

Я согласен с @Gintautas. Общее правило заключается в создании абстрактного модельного класса, если вам нужно повторно использовать поля модели и мета-параметры; используйте простой класс, если вам нужно повторно использовать другие свойства и методы.

В вашем случае я бы с абстрактным классом (из поля photo модели):

class PhotoModels(models.Model): 

    photo = models.ImageField(upload_to=u'something') 

    def photo_thumb(self): 
     if self.photo: 
      return u'<img src="%s" />' % (settings.MEDIA_URL + 
        '/thumbs/?h=64&w=80&c=50x0&p=' + self.photo.name) 
     else: 
      return u'(no photo)' 

    photo_thumb.short_description = u'Photo' 
    photo_thumb.allow_tags = True 
    photo_thumb.admin_order_field = 'photo' 

    class meta: 
     abstract = True 

class Something(PhotoModels):  
    title = models.CharField(max_length=200, default=u'') 
    text = models.CharField(max_length=250, default=u'', blank=True) 

class SomethingElse(PhotoModels):  
    name = models.CharField(max_length=200, default=u'') 
    foo = models.CharField(max_length=250, default=u'', blank=True) 
    photo.upload_to = u'something_else' 

    def __unicode__(self): 
     return self.title; 

... хотя это было бы законным точно также:

class PhotoModels: 

    def photo_thumb(self): 
     if self.photo: 
      return u'<img src="%s" />' % (settings.MEDIA_URL + 
        '/thumbs/?h=64&w=80&c=50x0&p=' + self.photo.name) 
     else: 
      return u'(no photo)' 

    photo_thumb.short_description = u'Photo' 
    photo_thumb.allow_tags = True 
    photo_thumb.admin_order_field = 'photo' 

class Something(models.Model, PhotoModels):  
    title = models.CharField(max_length=200, default=u'') 
    text = models.CharField(max_length=250, default=u'', blank=True) 
    photo = models.ImageField(upload_to=u'something') 

class SomethingElse(models.Model, PhotoModels):  
    name = models.CharField(max_length=200, default=u'') 
    foo = models.CharField(max_length=250, default=u'', blank=True) 
    photo = models.ImageField(upload_to=u'something_else') 

    def __unicode__(self): 
     return self.title; 
+0

Ваш второй пример, кажется, работает нормально, что оставляет мне интересно, что причина для абстрактных классов Django ... кажется ненужным, если нормальное наследование работает. Я думаю, что ошибка, которую я совершила при попытке этого раньше, заключалась в расширении модели. Моделя с базовым классом вместо того, чтобы ничего не расширять. –

+0

Я думаю, что ответ лежит между деталями gory метакласса модели Django. Я уверен, что из-за кунг-фу, который существует там для рамки '_meta' (помните, как поля модели меняются во время инициализации класса), ограничения наследования и мета-параметры, которые вам нужны, чтобы иметь« Модели »в качестве базового класса для все, чтобы петь правильно - в этом случае, если это не абстрактно, определение схемы db будет создано.Я никогда не пробовал это самостоятельно, но я уверен, что что-то причудливое должно произойти, если вы наследуете класс с полями модели, у которого нет базы «Model». –

+0

Что-то причудливое случается ... Я только что обнаружил это. Методы, кажется, работают отлично, но свойства модели. * Свойств нет. –

Смежные вопросы