Resuable модель членов в Джанго - PullRequest
1 голос
/ 13 августа 2010

У меня есть модель django, подобная этой:

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;

Я чувствую, что это нарушает DRY по очевидным причинам.Мой вопрос, могу ли я вставить это куда-нибудь еще:

    # ...
    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.Любая помощь приветствуется.

Ответы [ 4 ]

3 голосов
/ 13 августа 2010

Я согласен с @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;
1 голос
/ 13 августа 2010

Другим решением может быть создание подкласса 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) для динамического доступа к полю.Так что да, мы гарантируем, что у нас есть поле photo .

1 голос
/ 13 августа 2010

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

0 голосов
/ 13 августа 2010

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

http://docs.djangoproject.com/en/dev/topics/db/models/#abstract-base-classes

Я проверю это и подтвердлю.

...