【问题标题】:how to use image as option in django model form如何在 django 模型表单中使用图像作为选项
【发布时间】:2022-10-25 18:20:46
【问题描述】:

我正在尝试创建一个表单,我希望用户在其中提供一些选项作为图像,并且用户必须以黑白方式选择它们,但我不知道该怎么做我将图像放在 HTML 中向用户显示图像,但我也想将该图像选项保存在我的个人自述数据库中

这是我的代码

class SystemChoice (models.Model):
    name = models.CharField(max_length=200)
    img_link = models.URLField(blank=False)
    link = models.URLField(blank=False)

    def __str__(self):
        return self.img_link

class Personal_readme(models.Model):
    system_choice = [
        ('windows', 'windows'),
        ('linux', 'linux'),
        ('macOs', 'macOs'),
        ('unix', 'unix')
    ]
    work_status_Regex = RegexValidator(regex = "((http|https)://)(www.)?[a-zA-Z0-9@:%._\\+~#?&//=]{2,256}\\.[a-z]{2,6}\\b([-a-zA-Z0-9@:%._\\+~#?&//=]*)")
    name = models.CharField(max_length=70, blank=False)
    about_me = models.CharField(max_length=100, blank=True)
    work_status =  models.CharField(max_length=70, blank=True)
    work_status_link = models.URLField(validators = [work_status_Regex], blank=True)
    system = MultiSelectField(max_length=20, choices=system_choice,max_choices=4, blank=True )


    def __str__(self):
        return self.name

如您所见,我想通过使用模型为用户提供系统选择,该模型存储诸如名称图像链接和他们喜欢使用的系统的链接之类的信息,而不是我想提供图像选项的名称,这是为什么我正在使用图像链接,因此在我的 HTML 中我可以使用 img src 标签查看它,但无法执行 任何想法都会有所帮助

HTML

<form action="" method="POST" enctype="multipart/form-data">
    {% csrf_token %}
    {{ form.name|as_crispy_field }}
    {{ form.about_me|as_crispy_field }} 
    {{ form.work_status|as_crispy_field }}
    {{ form.work_status_link|as_crispy_field }}
    <img src="{{ form.system|as_crispy_field }}" alt="">    <input type="submit" value="Genrate File">
  </form>

输出

如您所见,它正在放置 URL,但我想显示图像而不是 url

视图.py

def home(request):
    if request.method == 'POST':
        form = Personal_Readme_form(request.POST)
        if form.is_valid():
            form.save()
            return redirect('request:preview')
    else:
        form = Personal_Readme_form()
    return render(request, 'home.html', {'form': form})

表格.py

class Personal_Readme_form(forms.ModelForm):
    class Meta:
        model = Personal_readme
        fields = '__all__'
        labels = {
            'name':'Your Name',
            'about':'About Yourself',
            'work_status':'Your Current work status',
            'resume_link':'Your Resume',
            'work_status':'Your current status',
            'system':'I prefer working on',
        }
        widgets = {
            'name': forms.TextInput(attrs={'placeholder': 'Type your name'}),
            'about_me': forms.Textarea(attrs={'placeholder': 'A short summary about yourself'}),

            'project1': forms.TextInput(attrs={'placeholder':'Name of your project'}),
    
            'project2': forms.TextInput(attrs={'placeholder':'Name of your project'}),
    
            'project3': forms.TextInput(attrs={'placeholder':'Name of your project'}),
    
            'project4': forms.TextInput(attrs={'placeholder':'Name of your project'}),
    
            'project5': forms.TextInput(attrs={'placeholder':'Name of your project'}),
    
            'work_status' : forms.TextInput(attrs={'placeholder': 'Your current status'}),

            'system' : forms.CheckboxSelectMultiple(),   
            
        }

【问题讨论】:

    标签: python django django-models django-views django-forms


    【解决方案1】:

    (1)不管你是否使用crispy_forms,最简单的方法就是更改模型SystemChoice__str__()。 字段“系统”的小部件是:forms.CheckboxSelectMultiple

    模型.py

    # other imports
    from django.utils.html import format_html
    
    # other code statements
    
    class SystemChoice (models.Model):
        name = models.CharField(max_length=200)
        img_link = models.URLField(blank=False)
        link = models.URLField(blank=False)
    
        def __str__(self):
            return format_html(f"{self.name}<br><img src='{self.img_link}' width='100px' />")
    

    (2)另一种方法是创建一个自定义的crispy_form 字段并使用{% crispy form %} 呈现表单。使用{{ form.system|as_crispy_field }} 以清晰的形式呈现单个字段不会像{% crispy form %} 呈现表单字段那样呈现字段。

    这里需要修改crispy_forms 模板。因此,通过创建新的 crispy_form 字段来创建新模板并指向该模板。在表单初始化方法中调用FormHelper 并用自定义字段包装system 字段。在这种情况下:在模板文件中调用{{ form.system|as_crispy_field }} 将无法正确呈现系统字段。所以需要致电{% crispy form %}。这意味着也要更新表单模板文件。

    <form action="" method="POST" enctype="multipart/form-data">
        {% crispy form %}
        <input type="submit" value="Genrate File">
    </form>
    

    表格.py

    # other imports
    from crispy_forms.helper import FormHelper
    from crispy_forms.layout import Field
    
    # other code statements
    
    class CrispyCheckboxImageSelectMultiple(Field):
        template = "<PATH_TO_APP_TEMPLATES_DIR>/checkbox_multiple_images.html"
    
    
    class Personal_Readme_form(forms.ModelForm):
        class Meta:
            # other code statements
            widgets = {
                # other field widgets
                "system": forms.CheckboxSelectMultiple(),
            }
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.helper = FormHelper(self)
            self.helper['system'].wrap(CrispyCheckboxImageSelectMultiple)
    

    checkbox_multiple_images.html

    {% load crispy_forms_field %}
    {% load l10n %}
    
    {% if field.is_hidden %}
        {{ field }}
    {% else %}
    
        <div class="form-group{% if 'form-horizontal' in form_class %} row{% endif %}">
        {% if label_class %}
            <div class="{% for offset in bootstrap_checkbox_offsets %}{{ offset }} {% endfor %}{{ field_class }}">
        {% endif %}
            
        <{% if tag %}{{ tag }}{% else %}div{% endif %} id="div_{{ field.auto_id }}" class="{% if not field|is_checkbox %}form-group{% if 'form-horizontal' in form_class %} row{% endif %}{% else %}{%if use_custom_control%}custom-control custom-checkbox{% else %}form-check{% endif %}{% endif %}{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
            {% if field.label and not field|is_checkbox and form_show_labels %}
            {# not field|is_radioselect in row below can be removed once Django 3.2 is no longer supported #}    
            <label {% if field.id_for_label and not field|is_radioselect %}for="{{ field.id_for_label }}" {% endif %}class="{% if 'form-horizontal' in form_class %}col-form-label {% endif %}{{ label_class }}{% if field.field.required %} requiredField{% endif %}">
                    {{ field.label|safe }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
                </label>
            {% endif %}
    
            {% include '<PATH_TO_TEMPLATES_DIRECTORY_OF_YOUR_APP>/checkbox_image_options.html' %}
    
        </{% if tag %}{{ tag }}{% else %}div{% endif %}>
    
        {% if label_class %}
            </div>
        {% endif %}
        </div>
    {% endif %}
    

    checkbox_image_options.html

    {% load crispy_forms_filters %}
    {% load l10n %}
    
    <div here {% if field_class %}class="{{ field_class }}"{% endif %}{% if flat_attrs %} {{ flat_attrs|safe }}{% endif %}>
    
        {% for group, options, index in field|optgroups %}
            {% if group %}<strong>{{ group }}</strong>{% endif %}
            {% for option in options %}
            <div class="{%if use_custom_control%}custom-control custom-checkbox{% if inline_class %} custom-control-inline{% endif %}{% else %}form-check{% if inline_class %} form-check-inline{% endif %}{% endif %}">
                <input type="checkbox" class="{%if use_custom_control%}custom-control-input{% else %}form-check-input{% endif %}{% if field.errors %} is-invalid{% endif %}" name="{{ field.html_name }}" value="{{ option.value|unlocalize }}" {% include "bootstrap4/layout/attrs.html" with widget=option %}>
                <label tester class="{%if use_custom_control%}custom-control-label{% else %}form-check-label{% endif %}" for="{{ option.attrs.id }}">
                    
                    {% comment %} Image tag added here {% endcomment %}
                    <img src="{{ option.label }}" width="100px" />
    
                </label>
                {% if field.errors and forloop.last and not inline_class and forloop.parentloop.last %}
                    {% include 'bootstrap4/layout/field_errors_block.html' %}
                {% endif %}
            </div>
            {% endfor %}
        {% endfor %}
    
        {% if field.errors and inline_class %}
        <div class="w-100 {%if use_custom_control%}custom-control custom-checkbox{% if inline_class %} custom-control-inline{% endif %}{% else %}form-check{% if inline_class %} form-check-inline{% endif %}{% endif %}">
            {# the following input is only meant to allow boostrap to render the error message as it has to be after an invalid input. As the input has no name, no data will be sent. #}
            <input type="checkbox" class="custom-control-input {% if field.errors %}is-invalid{%endif%}">
            {% include 'bootstrap4/layout/field_errors_block.html' %}
        </div>
        {% endif %}
    
        {% include 'bootstrap4/layout/help_text.html' %}
    </div>
    

    【讨论】:

    • 非常感谢你,这对我有很大帮助,帮助我今天学到了一些新东西,再次感谢你
    【解决方案2】:

    为系统变量创建模型更加直接且易于管理。

    class SystemChoice (models.Model):
        name = models.CharField(max_length=200)
        img =  models.ImageField(default='default.png', upload_to='OS_logos',null=False, blank=False)
        link = models.URLField(max_length=400)
    
    class Personal_readme(models.Model):
        work_status_Regex = RegexValidator(regex = "((http|https)://)(www.)?[a-zA-Z0-9@:%._\+~#?&//=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%._\+~#?&//=]*)")
        name = models.CharField(max_length=70, blank=False)
        about_me = models.CharField(max_length=100, blank=True)
        work_status =  models.CharField(max_length=70, blank=True)
        work_status_link = models.URLField(validators = [work_status_Regex], blank=True)
        system = models.ManyToManyField(SystemChoice, blank=True)
    
        def __str__(self):
            return self.name
    

    你可以在你的模板中做到这一点

    {% for obj in your_context_for_Personal_readme.system.all %}
            {{ obj.name  }}
            <img src="{{ obj.img.url}}">
    {% endfor %}
    

    存储图像但数据库的解决方案

    如果您不想将图像存储在数据库中,可以使用 Cloudinary

    pip install cloudinary
    

    设置.py

    import cloudinary
    import cloudinary.uploader
    import cloudinary.api
    
    INSTALLED_APPS = [
        ...
        'cloudinary'
    ]
    
    cloudinary.config( 
      # Get them from **Cloudinary dashboard page**
      cloud_name = "YOUR_CLOUD_NAME", 
      api_key = "YOUR_API_KEY", 
      api_secret = "YOUR_API_SECRET" 
    )
    

    模型.py

    from cloudinary.models import CloudinaryField
    
    class SystemChoice (models.Model):
        name = models.CharField(max_length=200)
        img = CloudinaryField('image')
        link = models.URLField(max_length=400)
    
    class Personal_readme(models.Model):
        work_status_Regex = RegexValidator(regex = "((http|https)://)(www.)?[a-zA-Z0-9@:%._\+~#?&//=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%._\+~#?&//=]*)")
        name = models.CharField(max_length=70, blank=False)
        about_me = models.CharField(max_length=100, blank=True)
        work_status =  models.CharField(max_length=70, blank=True)
        work_status_link = models.URLField(validators = [work_status_Regex], blank=True)
        system = models.ManyToManyField(SystemChoice, blank=True)
    
        def __str__(self):
            return self.name
    
    class photos(models.Model):
    

    迁移

    python manage.py makemigrations
    python manage.py migrate
    

    和模板是一样的:

    {% for obj in your_context_for_Personal_readme.system.all %}
            {{ obj.name  }}
            <img src="{{ obj.img.url}}">
    {% endfor %}
    

    【讨论】:

    • @nigel239 对不起?逻辑是什么?这是最糟糕的。我没有尝试在其中获取图像名称。
    • 如果我使用图像链接而不是使用实际图像怎么办我如何放入模板 <img> 以便它显示图像,这样我就不必存储图像任何想法,因为我无法将图像带入模板
    • 我正在使用模型表格
    • 我已经向您展示了如何使用 Cloudinary 在云上存储图像。我希望这能帮到您
    • 你告诉我如何从数据库中检索图像并将它们显示在模板上,但我想知道一种方法,给用户一个表格,这样他就可以选择图像选项并保存他选择 windows 和 linux 的信息它首选的工作系统的图像
    【解决方案3】:

    有多种方法可以做到这一点,具体取决于 OP 想要在模型、模板等中做什么。

    在模型层面,OP可以

    1. Use choices attribute in the model field。如果知道图像不会更改,请使用此方法。 OP 可能希望将 OP 的系统模型字段更改为 CharField 或 FilePathFieldRead more about choices here

    2. Create a specific model / database table with a ForeignKey,或喜欢enes islam mentions in the other answer。我更喜欢这种方法,因为它提供了更大的灵活性,以防人们想要添加/编辑/删除图像。

      一旦模型被覆盖,就有不同的方式可以显示它。例如

      1. Fill the form field dynamically when the form is instantiated

      2. Render choices manuallyThis answer has a relatively easy to understand overview

    【讨论】:

    • 我认为有一些误解,我刚刚更新了我的问题,请查看
    • @Blackranger 你试过&lt;img src="{{ form.system.img_link|as_crispy_field }}" alt=""&gt; 吗?
    • 是的,我确实尝试过,然后它在 / |as_crispy_field 处抛出错误 CrispyError 传递了一个无效或不存在的字段
    • 正如你所看到的,我已经在模型中返回了 img_link,所以这没有意义吗?
    • @Blackranger 你能分享视图和表单的代码吗(如果它与视图分开)?
    猜你喜欢
    • 1970-01-01
    • 2012-10-20
    • 2010-10-19
    • 2014-01-10
    • 1970-01-01
    • 2023-02-09
    • 1970-01-01
    • 1970-01-01
    • 2018-07-14
    相关资源
    最近更新 更多