django中可重复使用的模态成员

时间:2010-08-12 23:29:58

标签: python django inheritance django-models dry

我有一个像这样的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 个答案:

答案 0 :(得分: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;

答案 1 :(得分:1)

当然可以重复使用代码。只需将其分解为基类,并使您的类继承自该基类。这应该工作得很好。只是不要忘记基类要么继承自models.Model本身(然后我会建议making it abstract),要么你可以将可重用的代码放在mixin中;这意味着你的两个类都将继承自两个models.Model 新的mixin基类。

答案 2 :(得分: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,如果您使用的是另一个使用抽象模型的解决方案,则无法保证。

编辑:请注意,您可以使用getattr(self, name)动态访问该字段。所以,是的,保证我们有一些照片字段。

答案 3 :(得分:0)

也许我太早问了......我认为抽象基类可能就是答案。

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

我会检查并确认。