Django - 多个字段搜索问题

时间:2013-01-31 13:30:39

标签: django

我正在尝试构建一个相对简单的搜索表单,允许用户搜索三个搜索字段之一或三者的任意组合。结果应根据给定的术语过滤查询集。这是来自search_form.html的表单:

<form class="form-horizontal" action="/search/" method="get">
    <legend>Generate a Quiz:</legend>
    <div class="control-group">
        <label class="control-label" for="q">Search term</label>
        <div class="controls">
            <input type="text" name="q" placeholder="Search term" autocomplete="on"/>
        </div>
    </div>  
    <div class="control-group">
        <label class="control-label" for="yr">Year</label>
        <div class="controls">
            <input type="text" name="yr" placeholder="Year" autocomplete="on"/>
        </div>
    </div>  
    <div class="control-group">
        <label class="control-label" for="ct">Category</label>
        <div class="controls">
            <input type="text" name="ct" placeholder="Category" autocomplete="on"/>
        </div>
    </div>  
    <div class="controls">
        <button type="submit" class="btn btn-primary">Fetch  &raquo;</button>
    </div>          
</form>

以下是我的观点:

def search(request):
    error = False
    if 'q' in request.GET:
        q = request.GET['q']
        yr = request.GET['yr']
        ct = request.GET['ct']
        if not ((q or yr) or ct):
            error = True
        else:
            question_set = Uroquiz.objects.filter(question__icontains=q).filter(year=yr).filter(cat_icontains=ct)
            paginator = Paginator(question_set, 1)
            page = request.GET.get('page')

            try:
                question_set = paginator.page(page)
            except PageNotAnInteger:
                question_set = paginator.page(1)
            except EmptyPage:
                question_set = paginator.page(paginator.num_pages)
            return render_to_response('search_results.html',
                {'question': question_set, 'query': q, 'year': yr, 'ct': ct})
    return render_to_response('search_form.html', {'error': error})

问题:

  1. 当我用'q'字段构建它时,它工作正常。当我在'yr'字段中链接到我的过滤器时,只要在表单中输入一年,它就可以正常工作。如果year(我的数据库中的一个整数字段)为空,则会为int()生成一个ValueError无效文字,其基数为10:''。

  2. 当我在“ct”字段中链接并尝试搜索所有字段时,我收到错误:无法将关键字“cat_icontains”解析为字段。我可以将过滤器更改为(cat = ct)并且它工作正常,但我应该可以在我的数据库的'cat'字段中使用_icontains。 我确定我遗漏了一些基本的东西,感谢任何帮助。

  3. 更新: 以下是基于以下答案的当前解决方案,允许搜索任何字段组合:

    def search(request):
        q = request.GET.get('q')
        yr = request.GET.get('yr', 0)
        ct = request.GET.get('ct')
        question_set = Uroquiz.objects.all()
    
        if q:
            if not (yr or ct):
                question_set = Uroquiz.objects.filter(question__icontains=q)
        if yr:
            if not (q or ct):
                question_set = Uroquiz.objects.filter(year=yr)
        if ct:
            if not (q or yr):
                question_set = Uroquiz.objects.filter(cat__icontains=ct)
        if (q and yr):
            if not ct:
                question_set = Uroquiz.objects.filter(question__icontains=q).filter(year=yr)
        if (q and ct):
            if not yr:
                question_set = Uroquiz.objects.filter(question__icontains=q).filter(cat__icontains=ct)
        if (yr and ct):
            if not q:
                question_set = Uroquiz.objects.filter(year=yr).filter(cat__icontains=ct)
        if ((q and yr) and ct):
            question_set = Uroquiz.objects.filter(question__icontains=q).filter(year=yr).filter(cat__icontains=ct)
        if not ((q or yr) or ct):
            return render_to_response('search_form.html')
        paginator = Paginator(question_set, 1)
        page = request.GET.get('page')
        try:
            question_set = paginator.page(page)
        except PageNotAnInteger:
            question_set = paginator.page(1)
        except EmptyPage:
            question_set = paginator.page(paginator.num_pages)
        return render_to_response('search_results.html',
            {'question': question_set, 'query': q, 'yr': yr, 'ct': ct})
    

    这似乎是解决这个问题的“忙碌”方式。是否有更惯用/ pythonic的方式来完成此搜索结果?

2 个答案:

答案 0 :(得分:4)

用户不会保证提交qyrct。您无法信任您的用户数据。如果用户没有提交任何这些参数,我认为这将导致错误KeyError

您可以使用get

为这些设置默认值
    q = request.GET.get('q')
    yr = request.GET.get('yr', 0)
    ct = request.GET.get('ct')

此外,您可以在找到每个参数时构建查询集。记住查询集是laziy

question_set = Uroquiz.objects.all()    
q = request.GET.get('q')
if q:
  question_set = question_set.filter(question__icontains=q)
etc

对于您的第二个问题,我相信,它与语法相关cat__icontains 2个下划线(而非filter(cat_icontains=ct),就像您的代码中一样)

答案 1 :(得分:1)

def search(request):
    q, yr, ct = "", "", ""
    question_set = Uroquiz.objects.filter()

    if request.GET.get('q'):
        question_set = question_set.filter(question__icontains=q)

    if request.GET.get('yr'):
        question_set = question_set.filter(year=yr)

    if request.GET.get('ct'):
        question_set = .filter(cat__icontains=ct)

    paginator = Paginator(question_set, 10)

    try:
        page = int(request.GET.get('page', '1'))
    except ValueError:
        page = 1

    try:
        question_set = paginator.page(page)
    except (EmptyPage, InvalidPage):
        question_set = paginator.page(paginator.num_pages)

    return render_to_response('search_results.html',
        {'question': question_set, 'query': q, 'year': yr, 'ct': ct})