web-dev-qa-db-fra.com

Django Admin Afficher l'image depuis Imagefield

Bien que je puisse montrer une image téléchargée dans list_display, est-il possible de le faire sur la page par modèle (comme dans la page que vous obtenez pour changer un modèle)?

Un modèle d'échantillon rapide serait:

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

L'administrateur par défaut affiche l'url de l'image téléchargée mais pas l'image elle-même.

Merci!

52
Jeff_Hd

Sûr. Dans votre classe de modèle, ajoutez une méthode comme:

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

et dans votre admin.py ajouter:

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

à votre ModelAdmin. Si vous souhaitez restreindre la possibilité de modifier le champ d'image, assurez-vous de l'ajouter à l'attribut exclude.

Remarque: Avec Django 1.8 et 'image_tag' uniquement dans readonly_fields, il ne s'affichait pas. Avec 'image_tag' uniquement dans les champs, il donnait une erreur de champ inconnu. Vous en avez besoin à la fois dans les champs et dans readonly_fields afin de s'afficher correctement.

106

En plus de la réponse de Michael C. O'Connor

Notez que dans Django v.1.9

image_tag.allow_tags = True

est obsolète et vous devez utiliser format_html (), format_html_join () ou mark_safe () à la place

Donc, si vous stockez vos fichiers téléchargés dans votre dossier public/répertoire, votre code devrait ressembler à ceci:

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'

et dans votre admin.py ajoutez:

fields = ['image_tag']
readonly_fields = ['image_tag']
52
palamunder

Cela peut être fait en admin sans modifier le modèle

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)
24
Serjik

Pour Django 1.9 Pour afficher l'image au lieu du chemin du fichier dans les pages d'édition, utiliser ImageWidget est une bonne façon de le faire.

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)

tilisation:

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

Les images s'affichent pour les champs, thumbNail et detailImage

16
Venkat Kotra

Avec Django-imagekit vous pouvez ajouter n'importe quelle image comme celle-ci:

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
9
Risadinha

Bien qu'il existe de bonnes solutions fonctionnelles déjà partagées ici, je pense que le balisage non formel, comme les balises d'image auxiliaires, appartient aux modèles, n'est pas collé à Django widgets de formulaire ou généré dans le modèle classes admin. Une solution plus sémantique est:

Remplacements de modèles d'administration

Remarque: Apparemment, ma réputation n'est pas assez élevée pour publier plus de deux liens simples, j'ai donc créé des annotations dans le texte suivant et inclus les URL respectives au bas de cette réponse.

Depuis la documentation du site d'administration Django :

Il est relativement facile de remplacer la plupart des modèles utilisés par le module d'administration pour générer les différentes pages d'un site d'administration. Vous pouvez même remplacer certains de ces modèles pour une application spécifique ou un modèle spécifique.

Django's Django.contrib.admin.options.ModelAdmin (généralement accessible sous l'espace de noms Django.contrib.admin.ModelAdmin) présente une série de chemins de modèles possibles vers chargeur de modèles de Django dans l'ordre du plus spécifique au moins. Cet extrait a été copié directement à partir de 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)

Par conséquent, compte tenu de la documentation de remplacement du modèle d'administration et des chemins de recherche du modèle précités Django Django), supposons que l'on ait créé une application "articles" dans laquelle est définie une classe de modèle "Article". Si l'on veut remplacer ou étendre seulement la forme par défaut Django changement de site d'administration pour le modèle articles.models.Article, on exécuterait les étapes suivantes:

  1. Créez une structure de répertoires de modèles pour le fichier de remplacement.
    • Bien que la documentation ne le mentionne pas, le chargeur de modèles cherchera d'abord dans les répertoires d'application si APP_DIRS1 est défini sur True.
    • Parce que l'on veut remplacer le modèle de site d'administration Django admin par étiquette d'application et par modèle, la hiérarchie de répertoires résultante serait: <project_root>/articles/templates/admin/articles/article/
  2. Créez le (s) fichier (s) de modèle dans sa nouvelle structure de répertoires.
    • Seul le formulaire de modification administrateur doit être remplacé, alors créez change_form.html.
    • Le chemin absolu final sera <project_root>/articles/templates/admin/articles/article/change_form.html
  3. Remplacez complètement ou étendez simplement le modèle de formulaire de changement d'administrateur par défaut.
    • Je n'ai pu localiser aucune information dans la documentation Django concernant les données de contexte disponibles pour les modèles de site d'administration par défaut, j'ai donc été obligé de regarder le Django = code source.
      • Modèle de formulaire de modification par défaut: github.com/Django/django/blob/master/Django/contrib/admin/templates/admin/change_form.html
      • Quelques définitions pertinentes du dictionnaire contextuel se trouvent dans Django.contrib.admin.options.ModelAdmin._changeform_view et Django.contrib.admin.options.ModelAdmin.render_change_form

Ma solution

En supposant que mon nom d'attribut ImageField sur le modèle est "fichier", mon remplacement de modèle pour implémenter des aperçus d'image serait similaire à ceci:

{% 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 semble être l'instance de modèle à partir de laquelle le ModelForm a été généré. En passant, je n'utilise généralement pas de CSS en ligne mais cela ne valait pas un fichier séparé pour une seule règle.

Sources:

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

C'est comment cela a fonctionné pour Django 2.1 sans modifier models.py:

Dans votre modèle Hero, vous avez un champ d'image .:

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

Vous pouvez le faire comme ceci:

@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,
            )
    )
3
Alex Jolig

Mise à jour Django 2.1 pour Venkat Kotra réponse . La réponse fonctionne très bien sur Django 2.0.7 et ci-dessous. Mais donne une erreur au serveur 500 (si DEBUG=False) Ou donne

render() got an unexpected keyword argument 'renderer'

La raison en est qu'en Django 2.1: Support for Widget.render() methods without the renderer argument is removed. Donc, param renderer est maintenant obligatoire. Nous devons mettre à jour la fonction render() de AdminImageWidget pour inclure param renderer. Et cela doit être après attrs (avant kwargs si vous l'avez):

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))
1
John Pang