首页 > 解决方案 > 在 Django 中一次提交两个表单

问题描述

我正在研究一种ListView包括两种形式的方法,一种是搜索形式,一种是过滤形式。这两种形式最终都会queryset通过其get_queryset方法改变视图。我想让它在您搜索某些内容时保持过滤器,反之亦然。

它或多或少可以工作,但仍然存在一个错误:每当我搜索某些内容时,会出现一个不应该存在的“清除过滤器”按钮:

在此处输入图像描述

在模板中,搜索表单包含如下:

{% block search_form %}
  {% with action='dashboard:families' placeholder='Search Families' %}
    {% include '_search.html' %}
  {% endwith %}
{% endblock %}

_search.html在哪里

{% load get %}

<form action="{% url action %}" method="get" class="left search col s6 hide-on-small-and-down" novalidate>
  <div class="input-field">
    <input id="search" placeholder="{{ placeholder }}"
        autocomplete="off" type="search" name="q"
        value="{{ search_form.q.value.strip|default:'' }}"
        data-query="{{ search_form.q.value.strip|default:'' }}">
    <label for="search" class="active"><i class="material-icons search-icon">search</i></label>
    <i data-behavior="search-clear"
        class="material-icons search-icon"
        {% if not search_form.q.value %}style="display: none;"{% endif %}>close</i>
  </div>
  {% if filter_form %}
    {% for field in filter_form %}
      <input type="hidden" name="{{ field.name }}" value="{{ request.GET|get:field.name }}"/>
    {% endfor %}
  {% endif %}
</form>

并且自定义过滤器get只是实现了该dict.get方法:

from django import template

register = template.Library()


@register.filter
def get(dictionary, key):
    return dictionary.get(key)

简而言之,搜索表单包括一个隐藏的filter_form,它与搜索查询一起提交。

包含过滤器表单的模板部分内容如下:

          <form action={% url 'dashboard:families' %} method="GET" data-behavior="filters">
            <input type="hidden" name="q" value="{{ request.GET.q.strip }}"/>

            <div class="input-field col s2">
              {{ filter_form.guide }}
              <label class="active">Guide</label>
              {% if filter_form.is_guide_filled %}
                <a href="" class="clear"><i class="material-icons tiny">clear</i></a>
              {% endif %}
            </div>

            <div class="input-field col s2">
              {{ filter_form.status }}
              <label class="active">Status</label>
              {% if filter_form.is_status_filled %}
                <a href="" class="clear"><i class="material-icons">clear</i></a>
              {% endif %}
            </div>

            <div class="input-field col s2">
              {{ filter_form.package }}
              <label class="active">Company / Package</label>
              {% if filter_form.is_package_filled %}
                <a href="" class="clear"><i class="material-icons tiny">clear</i></a>
              {% endif %}
            </div>

            <div class="input-field col s2">
              {{ filter_form.next_outreach }}
              <label>Outreach</label>
              {% if filter_form.is_next_outreach_filled %}
                <a href="" class="clear"><i class="material-icons tiny">clear</i></a>
              {% endif %}
            </div>

            <div class="input-field col s2">
              {{ filter_form.country }}
              <label class="active">Country</label>
              {% if filter_form.is_country_filled %}
                <a href="" class="clear"><i class="material-icons tiny">clear</i></a>
              {% endif %}
            </div>

            <div class="input-field col s1">
              {{ filter_form.vip }}
              <label>VIP</label>
              {% if filter_form.is_vip_filled %}
                <a href="" class="clear"><i class="material-icons tiny">clear</i></a>
              {% endif %}
            </div>

            <div class="input-field col s1">
              {{ filter_form.app }}
              <label>App</label>
              {% if filter_form.is_app_filled %}
                <a href="" class="clear"><i class="material-icons tiny">clear</i></a>
              {% endif %}
            </div>

            <a href="{% url 'dashboard:families' %}?q={{ request.GET.q.strip }}"
                data-behavior="clear-filters"
                class="btn-flat" {% if not filter_form.is_filled %}style="display: none;"{% endif %}>
              <i class="material-icons">close</i>Clear Filters
            </a>
          </form>

请注意,过滤器表单还包含一个以q搜索查询命名的隐藏字段。由于这是 a ,因此将其设置为CharField是有意义的。valuerequest.GET.q.strip

问题是,如果我进入调试器FamilyFilterForm,我会看到表单的数据是我期望的“字符串化”版本:

ipdb> self.data
<QueryDict: {'q': ['Christine'], 'status': ['None'], 'next_outreach': [''], 'country': ['None'], 'vip': [''], 'app': [''], 'guide': ['6'], 'package': ['None']}>

请注意如何将None值转换为字符串'None'。这会导致is_filled过滤器表单的属性“认为”一个值已被填写,而实际上并没有。

相反,我想让表单的数据等同于

ipdb> from django.http import QueryDict
ipdb> query_dict = QueryDict('q=Christine&guide=6')
ipdb> query_dict.dict()
{'q': 'Christine', 'guide': '6'}

特别是,如果没有应用过滤器,它应该只是一个空的QueryDict()or {}

当以这种方式在模板中传递时,如何避免request.GET值被“字符串化” ?value

标签: pythonhtmldjangodjango-templates

解决方案


我设法通过使用字段的属性正确地包含了隐藏filter_form(正确表示了多项选择字段) 。as_hidden所以_search.html模板变成了

<form action="{% url action %}" method="get" class="left search col s6 hide-on-small-and-down" novalidate>
  <div class="input-field">
    <input id="search" placeholder="{{ placeholder }}"
        autocomplete="off" type="search" name="q"
        value="{{ search_form.q.value.strip|default:'' }}"
        data-query="{{ search_form.q.value.strip|default:'' }}">
    <label for="search" class="active"><i class="material-icons search-icon">search</i></label>
    <i data-behavior="search-clear"
        class="material-icons search-icon"
        {% if not search_form.q.value %}style="display: none;"{% endif %}>close</i>
  </div>
  {% for field in filter_form %}
    {{ field.as_hidden }}
  {% endfor %}
</form>

同样,过滤器形式包含

{{ search_form.q.as_hidden }}

持久化搜索查询。


推荐阅读