【发布时间】:2018-10-20 07:19:53
【问题描述】:
我正在处理ListView,它包含In a Django template, how to specify a dictionary key which is itself an attribute? 中描述的过滤表单和搜索表单。当我提交搜索查询时,我希望它保留现有的过滤查询。
以前,我通过添加隐藏的<input> 元素来实现这一点,其中value 是使用自定义过滤器get 从request.GET 获得的,该过滤器调用QueryDict 的get 方法。我发现这样做的问题是,对于MultipleChoiceFields,例如,如果选择了多个选项,则只保留一个,因为get 方法只返回 last 值,如中所述https://docs.djangoproject.com/en/2.0/ref/request-response/#django.http.QueryDict.get.
我现在正在尝试不同的方法。使用自定义过滤器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
还有自定义过滤器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
我尝试将搜索表单修改如下:
{% 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>
有一些 Javascript 代码会在您按 Enter 时提交表单(无需按提交按钮):
$(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);
});
问题在于,当我通过选择过滤器并输入如下所示的搜索查询来尝试此操作时,
当我在视图的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 包含的查询?
(我注意到这个blog post 描述了一个类似问题的解决方案,但是代码 sn-p 看起来有点像意大利面条,我认为必须有更简单的方法。
【问题讨论】: