通过表单显示ImageField中的图像

时间:2015-02-27 11:56:00

标签: django django-models django-forms django-uploads

前奏

Here是显示ImageField的最简单方法。让我们假设我的表单中有10个字段,我不想在template.html中迭代所有字段,只是为了检查它是否是一个imageField并以不同的方式显示它。我想通过表单或小部件或this之类的方式来处理它。所以我想要离开template.html,因为它在下面。

template.html

<table>
    {{ form.as_table }}
</table>

并添加到 models.py 一个image_tag方法:

class UserProfile(Model):
  photo = ImageField(upload_to=PHOTO_DIRECTORY)
  contacts = TextField(null=True)
  ... others

  def image_tag(self):
    return u'<img src="%s" />' % self.photo.url

  image_tag.short_description = 'Image'
  image_tag.allow_tags = True

forms.py

class UserProfileForm(forms.ModelForm):

  class Meta:
    model = UserProfile
    fields = ('contacts', 'photo', 'image_tag', ...others)

我收到的错误Unknown field(s) (image_tag) specified for UserProfile是公平的。

我也尝试将它放在readonly_fields中,但它们不会以某种方式显示。我必须创建list_view吗?如果是的话应该在哪里?

我在这里想念什么?为什么image_tag方法应该是模型的一部分而不是形式?模型描述了数据应该如何在数据库中持久化,而不是如何通过表单呈现给用户。这应该是形式的一部分,不应该吗?如果我错了,请纠正我。我该如何解决这个问题?任何帮助将不胜感激!

3 个答案:

答案 0 :(得分:5)

正如Selcuk所提到的,最简单的解决方案是创建自己的小部件。

from string import Template
from django.utils.safestring import mark_safe
from django.forms ImageField

class PictureWidget(forms.widgets.Widget):
    def render(self, name, value, attrs=None):
        html =  Template("""<img src="$link"/>""")
        return mark_safe(html.substitute(link=value))

class UserProfileForm(forms.ModelForm):
    photo = ImageField(widget=PictureWidget)

答案 1 :(得分:2)

让我改进这个有趣的问题。我建议将图像输入和图像预览结合起来。子类FileInput小部件并重写render以连接其他html以显示预览图像和默认输入图像html。

from django.utils.safestring import mark_safe
from django import forms

class ImagePreviewWidget(forms.widgets.FileInput):
    def render(self, name, value, attrs=None, **kwargs):
        input_html = super().render(name, value, attrs=None, **kwargs)
        img_html = mark_safe(f'<br><br><img src="{value.url}"/>')
        return f'{input_html}{img_html}'

class UserProfileForm(forms.ModelForm):

    class Meta:
        model = UserProfile
        fields = '__all__'

    photo = forms.ImageField(widget=ImagePreviewWidget,)

答案 2 :(得分:0)

我还不能发表评论,因此需要通过“答案”添加。此便捷解决方案的所有功劳归于deathangel908。

我正在使用Django 2.1,在尝试接受的答案时遇到TypeError: render() got an unexpected keyword argument 'renderer'错误。此问题的解决方案可以在这里找到:https://stackoverflow.com/a/52039655/8002464

简而言之,对于Django 2.1及更高版本,解决方案必须稍作更改,并包含renderer=None。完全更新的解决方案:

from string import Template
from django.utils.safestring import mark_safe
from django.forms ImageField

class PictureWidget(forms.widgets.Widget):
    def render(self, name, value, attrs=None, renderer=None):
        html =  Template("""<img src="$link"/>""")
        return mark_safe(html.substitute(link=value))

class UserProfileForm(forms.ModelForm):
    photo = ImageField(widget=PictureWidget)

顺便说一句。快速的小改进,至少对于我的用例是添加媒体URL。这样一来,图像就会真正显示出来,而不会丢失错误的网址。但这可能只是因为我如何设置网址。

from django.conf import settings

[...]
    html = Template("""<img src="$media$link"/>""")
    return mark_safe(html.substitute(media=settings.MEDIA_URL, link=value))