【问题标题】:How to modify Bootstrap 4 form validation information presentation in Django?如何在 Django 中修改 Bootstrap 4 表单验证信息呈现方式?
【发布时间】:2021-03-11 05:08:08
【问题描述】:

我正在使用 Django 和 Bootstrap 4。我想自定义表单验证信息在我正在使用的模板中的显示方式。当当前模板发生错误时,无效的输入元素有红色轮廓,错误消息显示为弹出窗口。另外,正确输入的输入元素没有绿色轮廓,它们只是没有轮廓。

我想做以下事情:

  • 发生错误时在字段下方显示错误消息
  • 为输入正确的字段添加绿色轮廓

我尝试了多种解决方案,包括:

我的情况没有任何效果。

我当前的代码:

submit_job_listing.html(模板):

{% extends "base.html" %}
{% block title %} Submit a job {% endblock %}
{% block nav_item_post_a_job %}active{% endblock nav_item_post_a_job %}
{% block head %}
    {{ job_listing_form.media.css }}
{% endblock %}
{% block content %}

    <h1>Submit a job listing</h1>
    <div class="container">
      <form method="post" enctype="multipart/form-data">
          {% csrf_token %}
          <div class="row text-center">
            <h2> <b>Job listing information</b> </h2>
          </div>
          <br/>
          {% for field in job_listing_form.visible_fields %}
            <div class="form-group">
              <div class="row">
                <p>{{ field.label_tag }}</p>
              </div>
              <div class="row">
                {% if field.help_text %}
                  <p class="form-text text-muted">{{ field.help_text }}</p>
                {% endif %}
              </div>
              <div class="row">
                {{ field }}
              </div>
            </div>
          {% endfor %}
          <br/>
          <div class="row text-center">
            <h2> <b>Employer information</b> </h2>
          </div>
          <br/>
          {% for field in employer_form.visible_fields %}
            <div class="form-group">
              <div class="row">
                <p>{{ field.label_tag }}</p>
              </div>
              <div class="row">
                {% if field.help_text %}
                  <p class="form-text text-muted">{{ field.help_text }}</p>
                {% endif %}
              </div>
              <div class="row">
                {{ field }}
              </div>
            </div>
          {% endfor %}
        <input type="submit" value="Submit" class="btn btn-primary" />
      </form>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
      {{ job_listing_form.media.js }}
    </div>
{% endblock %}

views.py(相关部分):

def submitJobListing(request):
    if request.method == "POST":
        employer_form = EmployerForm(request.POST, request.FILES)
        job_listing_form = JobListingForm(request.POST, request.FILES)

        #check if employer with that name already exists
        employer_name = str(request.POST.get("name", ""))
        try:
            employer_with_the_same_name = Employer.objects.get(name=employer_name)
        except ObjectDoesNotExist:
            employer_with_the_same_name = None

        employer = None
        
        if (employer_with_the_same_name != None):
            employer = employer_with_the_same_name

        if employer == None and employer_form.is_valid() and job_listing_form.is_valid():
            employer = employer_form.save()

        job_listing = job_listing_form.save(commit=False)
        job_listing.employer = employer
        job_listing.save()
        job_listing_form.save_m2m()

        return SimpleTemplateResponse("employers/successful_job_listing_submission.html")

    else:
        employer_form = EmployerForm()
        job_listing_form = JobListingForm()

    context = {
        "employer_form": employer_form,
        "job_listing_form": job_listing_form,
    }

    return render(request, 'employers/submit_job_listing.html', context)

forms.py(相关部分):

class EmployerForm(forms.ModelForm):
    name = forms.CharField(max_length=100)
    #location = forms.CharField(widget=LocationWidget)
    short_bio = forms.CharField(widget=forms.Textarea)
    website = forms.URLField()
    profile_picture = forms.ImageField()

    def __init__(self, *args, **kwargs):
        super(EmployerForm, self).__init__(*args, **kwargs)
        for visible in self.visible_fields():
            if isinstance(visible.field.widget, (forms.widgets.TextInput, forms.widgets.Textarea, forms.widgets.URLInput, LocationWidget)):
                visible.field.widget.attrs['class'] = 'form-control'
            if isinstance(visible.field.widget, forms.widgets.ClearableFileInput):
                visible.field.widget.attrs['class'] = 'form-control-file'

    class Meta:
        model = Employer
        fields = ["name", "short_bio", "website", "profile_picture"]

class JobListingForm(forms.ModelForm):
        job_title = forms.CharField(max_length=100, help_text="What's the job title?")
        job_description = forms.CharField(widget=forms.Textarea)
        job_requirements = forms.CharField(widget=forms.Textarea)
        what_we_offer = forms.CharField(widget=forms.Textarea)
        location = forms.CharField(widget=LocationWidget)
        remote = forms.BooleanField()
        job_application_url = forms.URLField()
        point_of_contact = forms.EmailField()
        categories = forms.ModelMultipleChoiceField(
                     queryset=Category.objects.all(),
                     widget=forms.CheckboxSelectMultiple,
                     required=True)

        def __init__(self, *args, **kwargs):
            super(JobListingForm, self).__init__(*args, **kwargs)
            for visible in self.visible_fields():
                if isinstance(visible.field.widget, (forms.widgets.TextInput, forms.widgets.Textarea, forms.widgets.URLInput, forms.widgets.EmailInput, LocationWidget)):
                    visible.field.widget.attrs['class'] = 'form-control'
                if isinstance(visible.field.widget, (forms.widgets.CheckboxInput, forms.widgets.CheckboxSelectMultiple)):
                    visible.field.widget.attrs['class'] = 'form-check'

        class Meta:
            model = JobListing
            fields = ["job_title", "job_description", "job_requirements", "what_we_offer", "location", "remote", "job_application_url", "categories", "point_of_contact"]

谁能告诉我怎样才能达到我想要的效果?

更新 1:

我尝试添加检查field.errors 的代码,但它不起作用。

这是submit_job_listing.html 模板文件:

{% extends "base.html" %}
{% load widget_tweaks %}
{% block title %} Submit a job {% endblock %}
{% comment %} https://stackoverflow.com/questions/50028673/changing-active-class-in-bootstrap-navbar-not-staying-in-inherited-django-templa {% endcomment %}
{% block nav_item_post_a_job %}active{% endblock nav_item_post_a_job %}
{% block head %}
    {{ job_listing_form.media.css }}
    <!---
    <style>
        input, select {width: 100%}
    </style>
    --->
{% endblock %}
{% block content %}

{% comment %}
https://simpleisbetterthancomplex.com/article/2017/08/19/how-to-render-django-form-manually.html
{% endcomment %}

    <h1>Submit a job listing</h1>
    <div class="container">
      <form method="post" enctype="multipart/form-data">
          {% csrf_token %}
          <div class="row text-center">
            <h2> <b>Job listing information</b> </h2>
          </div>
          <br />
          <div class="row text-center">
            <p> <b>Note: Fields marked with an asterisk (*) are required</b> </p>
          </div>
          <br/>
          {% for field in job_listing_form.visible_fields %}
            <div class="form-group">
              <div class="row">
                <p>{{ field.label_tag }}{{ field.field.required|yesno:"*," }}</p>
              </div>
              <div class="row">
                {% if field.help_text %}
                  <p class="form-text text-muted">{{ field.help_text }}</p>
                {% endif %}
              </div>
              <div class="row">
                {{ field }}
                <p> {{ field.errors }} </p>
                {% if field.errors %}
                  <div class="border-bottom-danger">
                      {{ field.errors }}
                  </div>
                {% endif %}
              </div>
            </div>
          {% endfor %}
          <br/>
          <div class="row text-center">
            <h2> <b>Employer information</b> </h2>
          </div>
          <br />
          <div class="row text-center">
            <p> <b>Note: Fields marked with an asterisk (*) are required</b> </p>
          </div>
          <br/>
          {% for field in employer_form.visible_fields %}
            <div class="form-group">
              <div class="row">
                <p>{{ field.label_tag }}{{ field.field.required|yesno:"*," }}</p>
              </div>
              <div class="row">
                {% if field.help_text %}
                  <p class="form-text text-muted">{{ field.help_text }}</p>
                {% endif %}
              </div>
              <div class="row">
                {{ field }}
              </div>
            </div>
          {% endfor %}
        <input type="submit" value="Submit" class="btn btn-primary" />
      </form>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
      {{ job_listing_form.media.js }}
    </div>
{% endblock %}

当我只单击提交按钮而不输入任何内容时,所有输入都有一个红色轮廓,但没有任何内容打印为field.errors。我不知道为什么会这样。 为什么会这样?

【问题讨论】:

    标签: css django twitter-bootstrap django-views django-templates


    【解决方案1】:
    {% load widget_tweaks %}
    
    <div class="col-12 col-md-6">
                            <div class="form-group">
                                <label for="{{ form.field1.id_for_label }}" class="text-capitalize">{{ form.field1.label|title }}{% if form.field1.field.required %}<span class="text-danger ml-1">*</span>{% endif %}</label>
    
                                {% if form.is_bound %}
                                    {% if form.field1.errors %}
                                        {% render_field form.name class="form-control is-invalid" %}
                                        {% for error in form.field1.errors %}
                                            <div class="invalid-feedback">
                                            {{ error }}
                                            </div>
                                        {% endfor %}
                                    {% else %}
                                        {% render_field form.field1 class="form-control is-valid" %}
                                    {% endif %}
                                {% else %}
                                    {% render_field form.field1 class="form-control" %}
                                {% endif %}
    
                                {% if form.field1.help_text %}
                                    <small class="form-text text-muted">{{ form.field1.help_text }}</small>
                                {% endif %}
                            </div>
                        </div>
    </div>
    

    【讨论】:

    • 在您的代码中,您正在循环访问我提到的所有字段,以保留每个字段手册。因此,在您的情况下,您必须将 field1 替换为您拥有的正确字段
    【解决方案2】:

    你试过在模板中调试吗?

    我做了你想要实现的事情:

    <form method="post"> {% csrf_token %}
        {% for field in form %}
            <div class="form-group">
                {{ field }}
            <label class="control-label" for="{{ field.id_for_label }}">{{ field.label }}</label>
                {% if field.errors %}
                    <div class="border-bottom-danger">
                        {{ field.errors }}
                    </div>
                {% endif %}
            </div>
        {% endfor %}
        <button class="btn btn-block" type="submit">Submit</button>
    </form>
    

    地点:

    1. {{ field }} 是输入,您在其中正确添加 visible.field.widget.attrs['class'] = 'form-control'
    2. 然后,您想要(我猜)的错误存储在该字段中,因此如果有的话,您可以使用{{ field.errors }} 获取它。

    你的代码和我的不同之处在于我使用的是field.errors而不是if field.help_text,希望对你有帮助。

    我建议您在模板中放置断点,然后分析您的form 对象。然后你可以在你的前端做任何你想做的事情。

    1. 如果没有错误: 将类 outline-green 添加到您的输入包装器(&lt;div class="row")
    2. 如果出现错误:在输入下方的 div 中显示错误

    PS : 如果你想概述输入,而不是行包装,你可以通过 css 来完成(或者如果你正在使用它,最好使用 Sass):

    .row.outline-green > input{
       border: 1px solid green;
    }
    <div class="row outline-green">
    {{ field }}
    </div>

    【讨论】:

    • 对此我有两个问题:1) 如何在模板中放置断点?我正在使用 Atom 和终端 - 我需要为此使用其他东西吗? 2) 我更新了我的问题 - field.errors 似乎是空的。你能解释一下为什么会这样吗?
    • 1) Check on this thread。就个人而言,我正在使用 pycharm pro。 2)你真的得到{{ field.help_text }}的错误吗?尝试放置一些断点,以查看job_listing_form 和employer_form 是如何填充的。如果您不能在模板中,请在返回上下文之前尝试在视图中。使用断点进行调试将为您节省大量时间。
    • 当前模板将None 打印为field.errors。我不是通过 PyCharm 设置断点(因为我只有社区版),而是通过您提供的链接中的第二个答案。断点仅在第一次渲染模板时被激活。如果我单击提交按钮,则不会再次触发断点。这对我来说很奇怪 - 我认为 Django 会在每个 POST 请求上重新呈现模板,即使它是无效的?也许这个错误与我的观点有关?
    • 删除条件{% if field.errors %}之前的&lt;p&gt; {{ field.errors }} &lt;/p&gt;。然后检查您的job_listing_form.visible_fields 是如何填充断点的。是否有任何变量带有您所期望的任何类型的错误。 PS:如果您需要在模板中进行深度调试(逐步),请试用 pycharm pro 及其试用版 30 天(还有学生版 1 年)。
    • field.errors 为空,因为消息“请填写此字段”。由网络浏览器呈现。即使我填写了其他输入字段并单击提交按钮,它实际上并没有向服务器发送 POST 请求,但浏览器只是呈现“请填写此字段”。再次。如何解决此浏览器功能,以便测试我的错误报告功能?
    猜你喜欢
    • 2013-12-23
    • 2019-01-08
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-07
    • 2020-06-23
    • 1970-01-01
    相关资源
    最近更新 更多