Django 管理员以内联形式显示外键图像字段的缩略图



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

产品(有很多)产品媒体

ProductMedia(有一个)AppMedia

我真正想要的是在Product中以内联形式查看AppMedia的媒体字段的缩略图。

例如,在Django管理中编辑产品,显示一个StackedOnline表单。它包含(目前)所有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以这种方式共享,以停止同一文件的多次上传,并与图像一起存储额外的元数据(此处未显示)。

我遇到了同样的问题。我希望我至少有一次尝试对你的情况有用:

我解决这个问题的第一次尝试(不覆盖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)

您应该查看外键的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')

你可以访问产品模型中的媒体对象,这将允许你把它放在你的管理内联表单中。也就是说,你会有(为了更简单的解释,我把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')

然后在你的管理员.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

希望我能正确理解你的问题,这对我有所帮助。此外,代码还没有经过测试,但我确信它应该可以工作。

最新更新