Django Admin Show Image来自Imagefield

时间:2013-04-30 19:13:40

标签: django django-admin

虽然我可以在list_display中显示上传的图像,但是可以在每个模型页面上执行此操作(如更改模型所获得的页面)?

快速样本模型将是:

Class Model1(models.Model):
    image = models.ImageField(upload_to=directory)

默认管理员显示已上传图片的网址,但不显示图片本身。

谢谢!

12 个答案:

答案 0 :(得分:102)

不确定。在模型类中添加如下方法:

def image_tag(self):
    return u'<img src="%s" />' % <URL to the image>
image_tag.short_description = 'Image'
image_tag.allow_tags = True

并在admin.py添加:

fields = ( 'image_tag', )
readonly_fields = ('image_tag',)

ModelAdmin。如果您想限制编辑图片字段的功能,请务必将其添加到exclude属性。

注意:只有readonly_fields中的Django 1.8和'image_tag'才会显示。仅在字段中使用'image_tag',它会产生未知字段的错误。您需要在字段和readonly_fields中才能正确显示。

答案 1 :(得分:50)

除了Michael C. O&#39; Connor的回答

请注意,在Django v.1.9中

image_tag.allow_tags = True

已弃用且you should use format_html(), format_html_join(), or mark_safe() instead

因此,如果您将上传的文件存储在公共/目录文件夹中,则代码应如下所示:

Class Model1(models.Model):
    image = models.ImageField(upload_to=directory)

    def image_tag(self):
        return mark_safe('<img src="/directory/%s" width="150" height="150" />' % (self.image))

    image_tag.short_description = 'Image'

并在您的admin.py中添加:

fields = ['image_tag']
readonly_fields = ['image_tag']

答案 2 :(得分:22)

  

可以在管理员中完成而无需修改模型

Shooter

答案 3 :(得分:16)

对于Django 1.9 要在编辑页面中显示图像而不是文件路径,使用ImageWidget是很好的方法。

from django.contrib.admin.widgets import AdminFileWidget
from django.utils.translation import ugettext as _
from django.utils.safestring import mark_safe
from django.contrib import admin


class AdminImageWidget(AdminFileWidget):
    def render(self, name, value, attrs=None):
        output = []
        if value and getattr(value, "url", None):
            image_url = value.url
            file_name = str(value)
            output.append(u' <a href="%s" target="_blank"><img src="%s" alt="%s" /></a> %s ' % \
                          (image_url, image_url, file_name, _('Change:')))
        output.append(super(AdminFileWidget, self).render(name, value, attrs))
        return mark_safe(u''.join(output))


class ImageWidgetAdmin(admin.ModelAdmin):
    image_fields = []

    def formfield_for_dbfield(self, db_field, **kwargs):
        if db_field.name in self.image_fields:
            request = kwargs.pop("request", None)
            kwargs['widget'] = AdminImageWidget
            return db_field.formfield(**kwargs)
        return super(ImageWidgetAdmin, self).formfield_for_dbfield(db_field, **kwargs)

<强>用法:

class IndividualBirdAdmin(ImageWidgetAdmin):
    image_fields = ['thumbNail', 'detailImage']

图片会显示字段thumbNaildetailImage

答案 4 :(得分:9)

使用django-imagekit,您可以添加以下任意图片:

from imagekit.admin import AdminThumbnail

@register(Fancy)
class FancyAdmin(ModelAdmin):
    list_display = ['name', 'image_display']
    image_display = AdminThumbnail(image_field='image')
    image_display.short_description = 'Image'

    readonly_fields = ['image_display']  # this is for the change form

答案 5 :(得分:7)

虽然这里已经分享了一些好的,功能性的解决方案,但我觉得非形式标记(如辅助图像标记)属于模板,而不是添加到Django表单小部件或在模型管理类中生成。更具语义性的解决方案是:

管理员模板覆盖

注意:显然我的声誉不足以发布两个以上的简单链接,因此我在下面的文字中创建了注释,并在此答案的底部包含了相应的网址。< / p>

来自Django Admin Site documentation

  

覆盖管理模块用于生成管理站点的各个页面的许多模板相对容易。您甚至可以为特定应用或特定模型覆盖其中一些模板。

Django的django.contrib.admin.options.ModelAdmin(通常在命名空间django.contrib.admin.ModelAdmin下访问)提供了一系列可能的Django's template loader模板路径,从最具体到最不具体。此代码段直接从django.contrib.admin.options.ModelAdmin.render_change_form复制:

return TemplateResponse(request, form_template or [
    "admin/%s/%s/change_form.html" % (app_label, opts.model_name),
    "admin/%s/change_form.html" % app_label,
    "admin/change_form.html"
], context)

因此,考虑到前面提到的Django管理模板覆盖文档和模板搜索路径,假设有人创建了一个应用程序“文章”,其中定义了一个模型类“文章”。如果想要覆盖或扩展模型articles.models.Article的默认Django管理站点更改表单,则可以执行以下步骤:

  1. 为覆盖文件创建模板目录结构。
    • 虽然文档没有提及,但如果APP_DIRS 1 设置为True,模板加载器将首先查看应用程序目录。
    • 因为想要按应用标签和模型覆盖Django管理站点模板,所以生成的目录层次结构将是:<project_root>/articles/templates/admin/articles/article/
  2. 在一个新的目录结构中创建模板文件。
    • 只需要覆盖管理员更改表单,因此请创建change_form.html
    • 最终的绝对路径为<project_root>/articles/templates/admin/articles/article/change_form.html
  3. 完全覆盖或只是扩展默认的管理员更改表单模板。
    • 我无法在Django文档中找到有关默认管理网站模板可用的上下文数据的任何信息,因此我不得不查看Django源代码。
      • 默认更改表单模板:github.com/django/django/blob/master/django/contrib/admin/templates/admin/change_form.html
      • 可以在中找到一些相关的上下文字典定义 django.contrib.admin.options.ModelAdmin._changeform_viewdjango.contrib.admin.options.ModelAdmin.render_change_form
  4. 我的解决方案

    假设模型上的我的ImageField属性名称是“file”,我实现图像预览的模板覆盖将类似于:

    {% extends "admin/change_form.html" %}
    
    {% block field_sets %}
    {% if original %}
    <div class="aligned form-row">
        <div>
            <label>Preview:</label>
            <img
                alt="image preview"
                src="/{{ original.file.url }}"
                style="max-height: 300px;">
        </div>
    </div>
    {% endif %}
    {% for fieldset in adminform %}
      {% include "admin/includes/fieldset.html" %}
    {% endfor %}
    {% endblock %}
    

    original似乎是生成ModelForm的模型实例。顺便说一句,我通常不使用内联CSS,但单个规则不值得单独的文件。

    来源:

    1. docs.djangoproject.com/en/dev/ref/settings/#app-dirs

答案 6 :(得分:2)

This is如何在django 2.1上工作而无需修改models.py

在您的Hero模型中,您有一个图像字段。

headshot = models.ImageField(null=True, blank=True, upload_to="hero_headshots/")

您可以这样做:

@admin.register(Hero)
class HeroAdmin(admin.ModelAdmin, ExportCsvMixin):

    readonly_fields = [..., "headshot_image"]

    def headshot_image(self, obj):
        return mark_safe('<img src="{url}" width="{width}" height={height} />'.format(
            url = obj.headshot.url,
            width=obj.headshot.width,
            height=obj.headshot.height,
            )
    )

答案 7 :(得分:1)

Venkat Kotra的answer的Django 2.1更新。答案在Django 2.0.7及更低版本上工作正常。但是给出服务器500错误(如果DEBUG=False)或给出

render() got an unexpected keyword argument 'renderer'

原因是在Django 2.1中:Support for Widget.render() methods without the renderer argument is removed.因此,参数renderer现在是必需的。我们必须更新render()的函数AdminImageWidget以包含参数renderer。并且必须在attrs之后(如果有kwargs之前):

class AdminImageWidget(AdminFileWidget):
    def render(self, name, value, attrs=None, renderer=None):
        output = []
        if value and getattr(value, "url", None):
            image_url = value.url
            file_name = str(value)
            output.append(u' <a href="%s" target="_blank"><img src="%s" alt="%s" /></a> %s ' % \
                      (image_url, image_url, file_name, _('Change:')))
        output.append(super(AdminFileWidget, self).render(name, value, attrs, renderer))
        return mark_safe(u''.join(output))

答案 8 :(得分:1)

Django ver。 3.0.3

models.py:

def image_tag(self):
    from django.utils.html import mark_safe
    return mark_safe('<img src="%s" width="100px" height="100px" />'%(self.image.url))
image_tag.short_description = 'Image'

admin.py:

list_display = ('image_tag', )

答案 9 :(得分:1)

我想自己弄清楚,这就是我想出的

@admin.register(ToDo)
class ToDoAdmin(admin.ModelAdmin):
    def image_tag(self, obj):
        return format_html('<img src="{}" width="auto" height="200px" />'.format(obj.img.url))

    image_tag.short_description = 'Image'

    list_display = ['image_tag']
    readonly_fields = ['image_tag']

答案 10 :(得分:0)

@palamunder的答案在Django 2.2上对我有用,但做了一些小的改动。

Model.py

from django.utils.safestring import mark_safe

class AdminCategory(models.Model):
    image = models.ImageField(_("Image"),
            upload_to='categories/',
            blank=True,
            default='placeholder.png')

    def image_tag(self):
        return mark_safe('<img src="%s" width="150" height="150" />' % (
            self.image.url))  # Get Image url

    image_tag.short_description = 'Image'

Admin.py

admin.site.register(
    AdminCategory,
    list_display=["image_tag"],
)

答案 11 :(得分:0)

如果需要在保存之前显示图像预览,则可以使用自定义django模板+ js

admin.py

class UploadedImagePreview(object):
    short_description = _('Thumbnail')
    allow_tags = True

    def __init__(self, image_field, template, short_description=None, width=None, height=None):
        self.image_field = image_field
        self.template = template
        if short_description:
            self.short_description = short_description
        self.width = width or 200
        self.height = height or 200

    def __call__(self, obj):
        try:
            image = getattr(obj, self.image_field)
        except AttributeError:
            raise Exception('The property %s is not defined on %s.' %
                (self.image_field, obj.__class__.__name__))

        template = self.template

        return render_to_string(template, {
            'width': self.width,
            'height': self.height,
            'watch_field_id': 'id_' + self.image_field  # id_<field_name> is default ID 
                                                        # for ImageField input named `<field_name>` (in Django Admin) 
        })


@admin.register(MyModel)
class MainPageBannerAdmin(ModelAdmin):
    image_preview = UploadedImagePreview(image_field='image', template='admin/image_preview.html',
                                         short_description='uploaded image', width=245, height=245)
    readonly_fields = ('image_preview',)
    
    fields = (('image', 'image_preview'), 'title')

image_preview.html

<img id="preview_{{ watch_field_id }}" style="display: none; width: {{ width }}px; height: {{ height }}px" alt="">

<script>
    function handleFileSelect(event) {
        var files = event.target.files; // FileList object
        // Loop through the FileList and render image files as thumbnails
        for (var i = 0, f; f = files[i]; i++) {
            // Only process image files
            if (!f.type.match('image.*')) continue;
            // Init FileReader()
            // See: https://developer.mozilla.org/en-US/docs/Web/API/FileReader
            var reader = new FileReader();
            // Closure to capture the file information
            reader.onload = (function () {
                return function (e) {
                    // Render background image
                    document.getElementById('preview_{{watch_field_id}}').src = e.target.result;
                    // Set `display: block` to preview image container
                    document.getElementById('preview_{{watch_field_id}}').style.display = 'block';
                };
            })(f);
            // Read in the image file as a data URL
            reader.readAsDataURL(f);
        }
    }

    // Change img src after change file input
    // watch_field_id — is ID for ImageField input
    document.getElementById('{{ watch_field_id }}').addEventListener('change', handleFileSelect, false);
</script>
相关问题