在Django中提交表单时如何保留现有查询字符串? [英] How to preserve the existing query string when submitting a form in Django?

查看:38
本文介绍了在Django中提交表单时如何保留现有查询字符串?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在处理 ListView ,其中包含过滤器表单和搜索表单,如

当我通过视图的 get 方法放入调试器时,我看到 request.GET 仅包含搜索查询,而不包含过滤器查询,尽管该 request.META ['HTTP_REFERER'] 确实显示了过滤器查询:

  ipdb>request.GET< QueryDict:{'q':['Christine']}>ipdb>request.META.get('HTTP_REFERER')'http://localhost:8000/dashboard/families?q =& guide = 6& guide = 4& next_outreach =& vip =& app =' 

简而言之,看来 request.GET 仅由表单中的< input> 元素决定,而不是由表单的 action ,其中包含其他查询参数.

如何使 request.GET 包含 HTTP_REFERER 所包含的查询?

(我注意到这博客文章描述了类似问题的解决方案,但是代码段看起来有点像意大利面条,我认为必须有一种更简单的方法.

解决方案

我终于通过在 search_form 中包含一个隐藏的 filter_form 来解决了这个问题.因此,在 _search.html 中的< form> 标记内,我添加了

  {%用于filter_form%中的字段}{{field.as_hidden}}{%endfor%} 

这利用了 as_hidden 该字段的属性.

I'm working on a ListView which contains both a filter form and search form as described in In a Django template, how to specify a dictionary key which is itself an attribute?. When I submit a search query, I would like it to retain the existing filter query.

Previously, I implemented this by adding hidden <input> elements of which the value was obtained from request.GET using a custom filter, get, which calls the QueryDict's get method. I found that the problem with this is that for MultipleChoiceFields, for example, if multiple choices are selected, only one is retained, since the get method only returns the last value as described in https://docs.djangoproject.com/en/2.0/ref/request-response/#django.http.QueryDict.get.

I'm now trying a different approach. Using the custom filter relative_url,

from django import template
from django.utils.http import urlencode
from django.http import QueryDict

register = template.Library()


@register.simple_tag
def relative_url(field_name, value, query_string=None):
    """
    Replace the key 'field_name' in the query_string with the given value.
    For example,

    relative_url('guide', 1, 'q=Christine') == '?q=Christine&guide=1'

    (After https://simpleisbetterthancomplex.com/snippet/2016/08/22/dealing-with-querystring-parameters.html)
    """
    url = urlencode({field_name: value})
    if query_string:
        query_dict = QueryDict(query_string, mutable=True)
        query_dict[field_name] = value
        url = query_dict.urlencode()
    return '?' + url

and the custom filter referer_query,

from urllib.parse import urlparse
from django import template

register = template.Library()


@register.filter
def referer_query(request):
    return urlparse(request.META.get('HTTP_REFERER')).query

I've tried to modify the search form as follows:

{% load relative_url %}
{% load referer_query %}


<form action="{% relative_url "q" search_form.q.value.strip|default:'' request|referer_query %}" 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>
</form>

There is some Javascript code which submits the form when you press Enter (without having to press a submit button):

  $(document).on('click', '[data-behavior="search-clear"]', function(e) {
    $('#search').val('').parents('form').submit();
  });

  $(function() {
    setSearchClearVisibility($('#search'));
  });

  $(document).on('keydown', '#search', function(e) {
    var $el = $(this);

    setTimeout(function() {
      setSearchClearVisibility($el);
    }, 10);
  });

  function setSearchClearVisibility(el) {
    if (el.val() === '') {
      $('[data-behavior="search-clear"]').hide();
    } else {
      $('[data-behavior="search-clear"]').show();
    }
  }

  $(document).on('keydown', '#search', function(e) {
    var $el = $(this);

    setTimeout(function() {
      if (e.keyCode !== 27) return;

      $('#search').val('').blur();
      setSearchClearVisibility($el);

      if ($el.data('query') !== '') {
        $('#search').parents('form').submit();
      }
    }, 10);
  });

The problem is that when I try this out by a selecting a filter and entering a search query as illustrated below,

when I drop into the debugger in the view's get method, I see that request.GET only contains the search query, not the filter queries, despite that request.META['HTTP_REFERER'] does show the filter queries:

ipdb> request.GET
<QueryDict: {'q': ['Christine']}>
ipdb> request.META.get('HTTP_REFERER')
'http://localhost:8000/dashboard/families?q=&guide=6&guide=4&next_outreach=&vip=&app='

In short, it seems that request.GET is determined only by the <input> elements in the form, and not by the form's action, which contains additional query parameters.

How can I make the request.GET include the query contained by the HTTP_REFERER?

(I've noticed that this blog post describes a solution to a similar problem, but the code snippet looks a bit spaghetti-like and I think there must be a simpler way).

解决方案

I finally solved the problem by including a hidden filter_form in the search_form. So in _search.html, within the <form> tags, I added

  {% for field in filter_form %}
    {{ field.as_hidden }}
  {% endfor %}

This makes use of the as_hidden property of the field.

这篇关于在Django中提交表单时如何保留现有查询字符串?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆