我的Django应用程序中有一个高级搜索表单,我想使用POST方法。使用GET会暴露出太多关于应用程序内部工作的信息。使用POST需要一些额外的工作来确保分页功能正确。
我找到了很多相关的答案:Paginating the results of a Django forms POST request
我决定将POST查询存储在会话数据中,以确保它可用于分页。我将整个POST作为QueryDict存储在会话中,如下所示:https://www.abidibo.net/blog/2014/09/19/paginating-results-django-form-post-request/的
由于某种原因,在表单验证成功并随后重定向之后,会话数据将丢失所有列表,并仅保留列表中的最后一个值作为单个项。
简化模型(实际模型要复杂得多):
class Organisation(models.Model):
name = Charfield()
location = Charfield()
industry = Charfield() # This is a choices field with 19 options
...
个字符
我有两个视图驱动搜索-搜索表单视图和搜索结果视图。
class OrganisationSearchFormView(FormView):
class Meta:
model = Organisation
form_class = OrganisationSearchForm
template_name = "organisation_search_form.html"
success_url = reverse_lazy("organisation_search_results")
def post(self, request):
form = OrganisationSearchForm(request.POST)
if form.is_valid():
request.session['post-query'] = self.request.POST
return self.form_valid(form)
else:
return self.form_invalid(form)
...
class OrganisationSearchResultListView(ListView):
model = Organisation
template_name = "organisation_search_results.html"
def get(self, request, *args, **kwargs):
# if there is not post query in the session data, redirect user back to the search form
if 'post-query' not in request.session:
return HttpResponseRedirect(reverse_lazy("organisation_search"))
return super().get(request, *args, **kwargs)
def get_queryset(self, **kwargs):
qs = super().get_queryset()
post_query = QueryDict('').copy()
post_query.update(self.request.session.get('post-query'))
search_org = post_query.get('search_org')
location = post_query.get('location')
search_industry = post_query.getlist('search_industry') # .getlist is required for a multivalue object.
qs = Organisation.objects.all()
# I filter the queryset based on the query parameters
的字符串
这里的工作流是表单视图提交(POST方法)给它自己进行验证。如果表单有效,则QueryDict对象存储在会话数据中。随后,会自动重定向(GET方法)到搜索结果视图。
表单视图->表单视图(验证)->结果视图
在重定向过程中,QueryDict中的任何列表都被剥离为单个值。我已经在表单视图post方法的表单验证块和results视图的get方法中放置了一个print语句,它显示了更改:
app-web-1 | [2023-07-17 15:31:03 +0000] [7] [DEBUG] POST /advsearch/i/
app-web-1 | <QueryDict: {'csrfmiddlewaretoken': ['************'], 'search_org': [''], 'search_industry': ['11', '21', '22', '23'], 'location': ['']}>
app-web-1 | [2023-07-17 15:31:04 +0000] [7] [DEBUG] GET /sr/i/
app-web-1 | <QueryDict: {'csrfmiddlewaretoken': ['************'], 'search_org': [''], 'search_industry': ['23'], 'location': ['']}>
型
我认为这个问题与dict的使用有关,而不是QueryDict在该链中的某个地方使用:django QueryDict only returns the last value of a list的
如果我将表单操作更改为POST直接到搜索结果视图,我不会遇到同样的问题,列表会保留并出现在会话数据中。即表单视图->结果视图
但是,我认为直接发布到结果视图,表单验证步骤被忽略了。是这样吗?
解决这个问题的最佳方法是什么?是否有一种方法可以使用:表单视图->表单视图(验证)->结果视图工作流?
任何建议或指导都是赞赏的。
1条答案
按热度按时间eqfvzcg81#
我遇到了一个类似的问题,并制定了一个解决方案,我认为可能对你的情况也有帮助。
总的来说:
request.POST
保存到request.session
时,django会序列化它,这个过程会导致request.POST
中包含多个值的字段被截断为一个值。根据示例,'search_industry': ['11', '21', '22', '23']
变为'search_industry': ['23']
。request.session.save()
之前序列化request.POST
中的任何多值字段。request.POST
中的哪些键与多值字段相关联。为此,我在表单中添加了一个隐藏的输入,该表单列出了所有的多项选择字段。下面是我在
requset.POST
中序列化和反序列化多值字段的函数:字符串
当你想要选择将
request.POST
保存到request.session
时,下面是一个可以添加到表单中的mixin:型
有了这个,在第一个视图中,你会这样:
型
在要使用已发布数据的视图中:
型