【问题标题】:Django Admin showing thumbnail of foreign key's imagefield in inline formDjango Admin 以内联形式显示外键图像字段的缩略图
【发布时间】:2012-07-21 14:26:23
【问题描述】:

我有一个简单的结构,有一个 Product 模型、一个 AppMedia 模型和一个 ProductMedia 连接表。

Product(有很多)ProductMedia

ProductMedia(有一个)AppMedia

我真正想要的是在 Product 的内联表单中看到 AppMedia 的媒体字段的缩略图。

例如在 Django admin 中编辑 Product,显示 StackedInline 表单。这包含(目前)所有 AppMedia 的下拉列表(选择)。

我需要的是缩略图。

任何帮助表示赞赏。

我确信这并不困难,但我正在苦苦挣扎。为 AppMedia 表单(媒体 ImageField 所在的位置)放置缩略图非常简单,但对于使用 AppMedia 作为 ForeignKey 的 ProductMedia 表单则不然。

基本模型...

class Product(models.Model):
    name             = models.CharField(max_length=100)

class AppMedia(models.Model):
    media           = models.ImageField(upload_to=appmedia_upload_to) #appmedia_upload_to defined elsewhere)

class ProductMedia(models.Model):
    title           = models.CharField(max_length=150)
    media           = models.ForeignKey(AppMedia)
    media_order     = models.IntegerField(default=0)
    product         = models.ForeignKey(Product)

AppMedia 以这种方式共享,以阻止同一文件的多次上传,并与图像一起存储额外的元数据(此处未显示)。

【问题讨论】:

    标签: django django-admin thumbnails imagefield


    【解决方案1】:

    您应该查看外键的 related_name 参数,这将允许您反向访问 ProductMedia,即,如果您将 ProductMedia 模型更改为:

    class ProductMedia(models.Model):
        title           = models.CharField(max_length=150)
        media           = models.ForeignKey(AppMedia)
        media_order     = models.IntegerField(default=0)
        product         = models.ForeignKey(Product, related_name='media')
    

    您可以访问 Product 模型中的媒体对象,这将允许您将其放入您的管理内联表单中。即你会有(为了更简单的解释,我将 ImageField 放在 ProductMedia 中):

    class Product(models.Model):
        name             = models.CharField(max_length=100)
    
        def admin_image(self):
            return '<img src="%s"/>' % (self.media.all()[0].image.url)
        admin_image.allow_tags = True
    
    class ProductMedia(models.Model):
        title           = models.CharField(max_length=150)
        image           = models.ImageField(upload_to=appmedia_upload_to) #appmedia_upload_to defined elsewhere)
        media_order     = models.IntegerField(default=0)
        product         = models.ForeignKey(Product, related_name='media')
    

    然后在你的 admin.py 中放:

    class ProductAdmin(admin.ModelAdmin):
        list_display = ('name', 'admin_image')
    
    admin.site.register(models.Product, ProductAdmin)
    

    https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.related_name

    希望我正确理解了您的问题,这对您有所帮助。代码也没有经过测试,但我很确定它应该可以工作。

    【讨论】:

    • 虽然理论上可以回答这个问题,但我们希望您在回答中包含链接文章的基本部分,并提供link for reference。如果不这样做,答案就会面临链接失效的风险。
    • 此解决方案使模型与管理应用程序紧密耦合。
    【解决方案2】:

    我有同样的问题。我希望我的至少一项尝试对您的情况有用:

    我第一次尝试解决这个问题(不覆盖ForeignKeyRawIdWidget)是:

    • 在内联管理中设置form 属性,其中应显示缩略图
    • 使用小部件将另一个字段添加到给定的表单类中,这将显示一个缩略图

    但是我放弃了这个解决方案,因为我认为我必须将有关缩略图的数据注入到表单构造函数的给定字段中,而且我认为这不是一个好的解决方案。

    我的下一个解决方案是在某些领域使用MultiWidget。在这种情况下,我不需要向表单添加另一个字段,并且我将拥有在小部件中显示缩略图所需的数据,而无需在构造函数中注入它们。

    class ThumbnailMultiWidget(MultiWidget):
    
       def decompress(self, value):
           #has to be overriden
           return [None,None]
    
    
    class ThumbnailWidget(Widget):
    
        def render(self, name, value, attrs=None):
           #not quite sure what is in `value`, I've not been so far
           return '<img src="%s"/>' % value.url
    
    
    class PhotoInlineForm(forms.ModelForm):
    
    
        def __init__(self, *args, **kwargs):
            super(PhotoInlineForm, self).__init__(*args, **kwargs)
    
    
            wdgts = [self.fields['media'].widget, ThumbnailWidget()]
            self.fields['media'].widget = ThumbnailMultiWidget(widgets=wdgts)
    
    
        class Meta:
            model = RecipePhoto
    

    但我也放弃了这个解决方案,因为我发现在ForeignKeyRawIdWidget(我使用的小部件)中实际上有一个实例的表示,其中包含我需要显示缩略图的所有数据。这就是我的最终解决方案:

    所以因为我的内联项目有 raw_id_field 用于选择内联记录,我可以简单地覆盖 ForeignKeyRawIdWidget 中的方法 label_for_value,它用于表示现有的内联记录。通常是__unicode__(我认为)。我继承了ForeignKeyRawIdWidget 并重写了这个方法来显示图像缩略图:

    class PhotoForeignKeyRawIdWidget(ForeignKeyRawIdWidget):
    
        def label_for_value(self, value):
            key = self.rel.get_related_field().name
            try:
                obj = self.rel.to._default_manager.using(self.db).get(**{key: value})
            except (ValueError, self.rel.to.DoesNotExist):
                return ''
            else:
                """
                there's utilized sorl.thumbnail, but you can return st like this:
                <img src='%s' /> % obj.media.url
                """
                return Template("""{% load thumbnail %}
                {% thumbnail image.image "120x120" crop="center" as one %}
                    <img src="{{ one.url }}" />
                {% endthumbnail %}""").render(Context({
                    'image': obj
                }))
    
    
    class AppMediaInlineAdmin(admin.TabularInline):
        model = AppMedia
        extra = 1
    
        def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
            if db_field.name == 'media':
                db = kwargs.get('using')
                kwargs['widget'] = PhotoForeignKeyRawIdWidget(db_field.rel, self.admin_site, using=db)
            return super(AppMediaInlineAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
    

    【讨论】:

      猜你喜欢
      • 2014-08-05
      • 2017-10-16
      • 2023-03-31
      • 1970-01-01
      • 2013-09-05
      • 2013-02-26
      • 2020-08-19
      • 2018-08-21
      • 2013-07-24
      相关资源
      最近更新 更多