Django Admin Показать изображение из Imagefield

Пока я могу показать загруженное изображение в list_display, возможно ли это сделать на каждой странице модели (как на странице, которую вы получаете для изменения модели)?

Быстрая модель образца:

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

Администратор по умолчанию показывает URL-адрес загруженного изображения, но не сам образ.

Спасибо!

Ответ 1

Конечно. В классе вашей модели добавьте такой метод:

def image_tag(self):
    from django.utils.html import escape
    return u'<img src="%s" />' % escape(<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.

Примечание: с Django 1.8 и 'image_tag' только в readonly_fields он не отображался. С 'image_tag' только в полях, он выдал ошибку неизвестного поля. Вам нужно это как в полях, так и в readonly_fields для корректного отображения.

Ответ 2

В дополнение к ответу Майкла С. О'Коннора

Обратите внимание, что в Django v.1.9

image_tag.allow_tags = True

устарела, и вы должны использовать format_html(), format_html_join() или mark_safe()

Поэтому, если вы храните свои загруженные файлы в папке public/directory, ваш код должен выглядеть следующим образом:

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']

Ответ 3

Это можно сделать в admin без изменения модели

from django.utils.html import format_html


class Model1Admin(admin.ModelAdmin):

    def image_tag(self, obj):
        return format_html('<img src="{}" />'.format(obj.image.url))

    image_tag.short_description = 'Image'

    list_display = ['image_tag',]

admin.site.register(Model1, Model1Admin)

Ответ 4

Для 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']

Изображения будут отображаться для полей, thumbNail и detailImage

Ответ 5

С 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

Ответ 6

Хотя здесь уже есть несколько хороших, функциональных решений, я считаю, что неформальная разметка, такая как вспомогательные теги изображений, принадлежит шаблонам, а не привязана к виджетам форм Django или сгенерирована в модельных административных классах. Более семантическое решение:

Переопределение шаблона администратора

Примечание. Очевидно, моя репутация недостаточно высока, чтобы публиковать более двух простых ссылок, поэтому я создал аннотации в следующем тексте и включил соответствующие URL-адреса в нижней части этого ответа.

Из документации сайта администратора Django:

Относительно легко переопределить многие из шаблонов, которые использует модуль администратора для создания различных страниц сайта администратора. Вы даже можете переопределить некоторые из этих шаблонов для конкретного приложения или конкретной модели.

Django django.contrib.admin.options.ModelAdmin (доступ к которому обычно осуществляется в пространстве имен django.contrib.admin.ModelAdmin) представляет серию возможных путей к шаблону для загрузчика шаблонов Django в порядке от наиболее специфических до менее. Этот фрагмент был скопирован непосредственно из 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", в котором определен класс модели "Article". Если кто-то хочет переопределить или расширить только стандартную форму изменения сайта администратора Django для модели articles.models.Article, можно выполнить следующие шаги:

  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_view и django.contrib.admin.options.ModelAdmin.render_change_form

Мое решение

Предполагая, что моим именем атрибута ImageField в модели является "файл", мой переопределение шаблона для реализации предварительного просмотра изображения будет примерно таким:

{% 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

Ответ 7

Вот как это работает для 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,
            )
    )

Ответ 8

Django 2.1 обновления для Venkat Котры ответа. Ответ отлично работает на 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. Итак, param 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))