在Django中提交表单时如何保留现有查询字符串? [英] How to preserve the existing query string when submitting a form in 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 MultipleChoiceField
s, 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屋!