【问题标题】:Django - how to perform search with multiple fields and ModelFormDjango - 如何使用多个字段和 ModelForm 执行搜索
【发布时间】:2012-05-03 15:19:41
【问题描述】:

我希望使用 ModelForm 类构建一个搜索表单,它允许用户通过特定字段而不是单个字段关键字搜索来搜索模型中的值。我还希望忽略空字段。

我研究了诸如 Haystack 和 Djapian 之类的搜索引擎选项,以及在 Django 中手动解决问题,但在使用多个字段进行查询时,我似乎无法返回结果。

这是我目前的观点,部分基于对本网站上一些类似问题的回答,以及记录在案的内容:

def search(request):
    error = False
    form = InfoForm()
    if 'field1' or 'field2' or 'field3' in request.GET:
        form = InfoForm(request.GET)
        if form.is_valid():
            cd = form.cleaned_data
            field1 = cd['field1']
            field2 = cd['field2']
            field3 = cd['field3']
            if not(field1 or field2 or field3):
                error = True
            else:
                query = Q()
                if request.GET['field1']:
                    query &= Q(field1__icontains=request.GET['field1'])
                if request.GET['field2']:
                    query &= Q(field2__icontains=request.GET['field2'])
                if request.GET['field3']:
                    query &= Q(field3__icontains=request.GET['field3'])

                results = PersonInfo.objects.filter(query).distinct()

                return render_to_response('search/personsearch.html',
                        {'query': query,
                         'field1': field1,
                         'field2': field2,
                         'field3': field3,
                         'results': results,
                        },
                    context_instance=RequestContext(request))

    return render_to_response('search/infosearch.html',
            {'error': error,
             'form': form},
        context_instance=RequestContext(request))

我还直接从文档中尝试了这个复杂的查询:

query = InfoModel.objects.get(
    Q(field1__icontains=field1) |
    Q(field2__icontains=field2) |
    Q(field3__icontains=field3)
)

在这两种情况下,查询字符串?field1=&field2=&field3= 都出现在 URL 的后面,并且页面返回字段中提供的字段值,如预期的那样;但如果所有字段都留空,则不会返回结果或生成错误。

我显然错过了一些东西,但对于我的生活,我无法弄清楚是什么。有没有其他人遇到过这个问题?

【问题讨论】:

  • 您需要隔离问题:您的视图有问题吗?还是查询?您的两个示例查询是不同的。第一个是 AND,第二个是 OR。 get 带有 3 个 OR 查询也在自找麻烦(使用过滤器代替多个预期结果)。我会放入 python 调试器并使用生成的查询。
  • 那么...你最终解决了这个问题吗?
  • 是的,但是我采取了一种稍微不同的方法,并且只检查了顶层if 'field1' in request.GET: 中的一个字段,我会将新代码作为完整答案发布,因为解决方案有点有趣.

标签: django search django-queryset django-forms


【解决方案1】:

在调试搜索视图时,我发现针对request.GET 的初始if 条件仅针对一个字段返回True,即使列出的所有字段实际上都在表单中。

从那里,实现我的多字段搜索的最简单方法是将.filter() 方法串在一起。搜索表单中的空字段会被忽略,正如所希望的那样,但如果所有字段都是空的,它会将您返回到搜索表单并正确处理错误。

def search(request):
    errors = []
    if 'field1' in request.GET:
        field1 = request.GET['field1']
        field2 = request.GET['field2']
        field3 = request.GET['field3']
        if not ((field1 or field2) or field3):
            errors.append('Enter a search term.')
        else:
            results = MyModel.objects.filter(
                field1__icontains=field1
            ).filter(
                field2__icontains=field2
            ).filter(
                field3__icontains=field3
            )
            query = "Field 1: %s, Field 2: %s, Field 3: %s" % (field1, field2, field3)
            return render_to_response('search/search_results.html',
                    {'results': results, 'query': query})
    return render_to_response('search/search_form.html',
            {'errors': errors})

这里的query 字符串现在只返回一个格式化的搜索词列表,您可以将其放入模板中。但是,如果需要,您也可以直接返回变量并将它们以另一种形式放置在搜索结果页面上。

分页也可以很好地用于搜索结果,这对于任何实际应用程序都是必不可少的。将上面的results 重命名为results_listthe Django documentation on Pagination 中的代码可以插入到您的视图中。我发现一个警告,您必须添加一个包含搜索字符串的新变量,并将其包含在分页链接的前面,否则当您单击定义的“下一个”或“上一个”链接时,您将返回到搜索表单在文档中。

最后,当您用 HTML 构建表单而不是依赖 Django 的 ModelForm 类时,它似乎效果最好。这样您就不必费力尝试调试表单验证错误,并且可以在视图函数中定义自己的验证规则。

【讨论】:

    猜你喜欢
    • 2014-12-25
    • 2021-11-22
    • 2020-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-14
    • 1970-01-01
    相关资源
    最近更新 更多