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

发布于 2024-09-14 03:32:37 字数 1881 浏览 8 评论 0原文

我有一个像这样的 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 也很陌生。任何帮助表示赞赏。

I have a django model like this:

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;

I feel like this violates DRY, for obvious reasons. My question is, can I stick this somewhere 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' 
    # ...

And then include it in relevant model classes with a single line of code? Or can photo_thumb be dynamically added to the appropriate classes somehow? I've tried classical and parasitic inheritance, but I may not be doing it right... I'm new to Django and fairly new to python also. Any help is appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

云巢 2024-09-21 03:32:37

我同意@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;

I agree with @Gintautas. The general rule of thumb is to create an abstract model class if you need to reuse model fields and meta options; use a simple class if you only need to reuse other properties and methods.

In your case I'd go with the abstract class (because of the photo model field):

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;

... although this would be legal just as well:

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;
瞄了个咪的 2024-09-21 03:32:37

另一个解决方案可能是创建 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)动态访问该字段。所以,是的,我们保证有一些照片字段。

Another solution may be to create a subclass of ImageField and override the contribute_to_class method:

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);

I think this is better because on calling the photo_thumb method you are expecting the existence of self.photo which is not guaranteed if you are using the other solution that use an abstract model.

EDIT: Note that you can use getattr(self, name) to dynamically access the field. So yes, it is guaranteed that we have some photo field.

凉栀 2024-09-21 03:32:37

当然,您可以重用该代码。只需将其分解为基类,然后使两个类都继承自该基类即可。那应该可以正常工作。只是不要忘记基类需要从 models.Model 本身继承(那么我建议 使其抽象),或者你可以将可重用的代码放在 mixin 中;这意味着您的两个类都将从 models.Model 和新的 mixin 基类继承。

Sure you can reuse the code. Just factor it out into a base class, and make both your classes inherit from that base class. That should work just fine. Just don't forget that the base class either needs to inherit from models.Model itself (then I would suggest making it abstract), or you can put the reusable code in a mixin; that means that your both classes will be inheriting from both models.Model and the new mixin base class.

九局 2024-09-21 03:32:37

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

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

我会检查并确认。

Maybe I asked too soon... I think abstract base classes may be the answer.

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

I'll check it out and confirm.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文