3

ユーザーがいくつかの異なるパラメーター (名前、年など) を使用してデータベースにクエリを実行し、フィールドを動的に追加し、それらをブール演算子で結合できるようにしたいと考えています。最終的な結果は、「年 = 1900 AND 名前 = ニワトリ AND 場所 = サンフランシスコ」のようになります。何らかのデータと一致することがわかっている値を持つフィールドを 1 つだけ試しても、何も返されないため、何か間違っていると思います (たとえば、Django シェルから .filter() を使用するとオブジェクトを取得できます)。 )。どうすれば修正できるか知っている人はいますか?

関連するビュー(ずさんなインデントは無視してください。すべてを調べて修正したくありませんでしたが、実際のコードでは正しいです):

class BaseSearchFormSet(BaseFormSet):
def clean(self):
    if any(self.errors):
        return self.errors
    queries = []
    valid_courses = ["appetizer","main","dessert"]
    valid_period = re.compile(r'\d\d\d0-\d\d\d5|\d\d\d5-\d\d\d0')
    valid_year = re.compile(r'\d{4}')
    multi_rows = ["year","period","course"]
    for x in xrange(0,self.total_form_count()):
        form = self.forms[x]
        query = form.cleaned_data.get("query")
        row = form.cleaned_data.get("row")
        if query in queries and row not in multi_rows:
            raise forms.ValidationError("You're already searching for %s.")
        queries.append(query)
        if row == "course" and query.lower() not in valid_courses:
            raise forms.ValidationError("%s is not a valid course option."%(form.cleaned_data["query"]))
        if row == "period" and not re.match(valid_period,query):
            raise forms.ValidationError("%s is not a properly formatted period. Valid five-year periods span either the first or second half of a decade. For example: 1910-1915, 1925-1930."%(form.cleaned_data["query"]))
        if row == "year" and not re.match(valid_year,query):
            raise forms.ValidationError("Please enter a four-digit year.")
def search(request):
errors = []
searchFormSet = formset_factory(F.SearchForm, extra=1,formset=BaseSearchFormSet)
if request.GET:
    formset = searchFormSet(request.GET)
    forms = []
    if formset.is_valid():
        for x in xrange(0,formset.total_form_count()):
            form = {}
            form["row"]= formset[x].cleaned_data.get("row",None)
            form["query"] = formset[x].cleaned_data.get("query",None)
            form["bools"] = formset[x].cleaned_data.get("bools",None)
            if form["query"]:
                q = form["query"]
            else:
                errors.append("no query found")
            if form["row"]:
                row = form["row"]
            else:
                errors.append("no row found")
            filter_keys = {"dish_name":Q(dish__name__icontains=q),
                "regex":Q(dish__full_name__regex=r'%s'%(q)),
                "course":Q(dish__classification=q.lower()),
                "year":Q(page__menu_id__year__exact=q),
                "period":Q(page__menu_id__period__exact=q),
                "location":Q(page__menu_id__location__icontains=q),
                "restaurant":Q(page__menu_id__restaurant__icontains=q)}
            forms.append(form)
        final_query=Q()
        def var_reduce(op,slice):
            if op == "and":
                return reduce(lambda x,y: x & y,slice)
            elif op == "or":
                return reduce(lambda x,y: x | y,slice)
        for x in xrange(len(forms)):
            try:
                try:
                    if final_query:
                        slice = [final_query,filter_keys[forms[x]["row"]],filter_keys[forms[x+1]["row"]]]
                    else:
                        slice = [filter_keys[forms[x]["row"]],filter_keys[forms[x+1]["row"]]]
                    final_query = var_reduce(forms[x]["bools"],slice)
                except IndexError:
                    if final_query:
                        slice = [final_query,filter_keys[forms[x]["row"]]]
                    else:
                        slice = [filter_keys[forms[x]["row"]]]
                    final_query = var_reduce(forms[x]["bools"],slice)
                items = MenuItem.objects.filter(final_query)
                return render_to_response("search_results.html",{"items":items,"formset":formset})
            except KeyError as e:
                errors.append(e)    
                formset = searchFormSet(None)
                return render_to_response("search_page.html",{"errors":errors,"formset":formset})
    else:   
        formset = searchFormSet(None)
        return render_to_response("search_page.html",{"errors":errors,"formset":formset})
else:
    formset = searchFormSet(None)
    return render_to_response("search_page.html",{"formset":formset})

モデル:

from django.db import models

class MenuItem(models.Model):
def format_price(self):
    return "${0:0<4,.2f}".format(float(self.price))
def __unicode__(self):
    return self.dish
dish=models.OneToOneField('Dish',to_field='mk')
price=models.CharField(max_length=5,blank=True)
page=models.OneToOneField('MenuPage')
mk=models.CharField(max_length=10,unique=True)
formatted_price = property(format_price)
class Menu(models.Model):
def period(self):#adapted from http://stackoverflow.com/questions/2272149/round-to-5or-other-number-in-python
    try:
        p=int(10*round(float(int(self.year))/10))
        if p < self.year:
            return "%s-%s"%(p,p+5)
        else:
            return "%s-%s"%(p-5,p)
    except (ValueError,TypeError):
        return ""
def __unicode__(self):
    if self.restaurant:
        return self.restaurant
    else:
        return self.mk
restaurant=models.TextField(unique=False,blank=True,null=True)
year=models.CharField(max_length=4,unique=False,blank=True,null=True)
location=models.TextField(unique=False,blank=True,null=True)
status=models.CharField(unique=False,max_length=20)
mk=models.CharField(max_length=8,unique=True,primary_key=True)
period=property(period) 
language = models.CharField(unique=False,max_length=30)
#objects=MenuManager()

class MenuPage(models.Model):
mk=models.CharField(max_length=10,unique=True)
menu_id=models.OneToOneField("Menu",to_field='mk')
#objects=MenuPageManager()
class Dish(models.Model):
def __unicode__(self):
    return self.name
full_name = models.TextField()
name=models.CharField(unique=True,max_length=255)
mk=models.CharField(max_length=10,unique=True)
class Classification(models.Model):
def __unicode__(self):
    if self.classification:
        return self.classification
    else:
        return "none"
dish=models.OneToOneField('dish',to_field='name')
classification=models.CharField(unique=False,max_length=9)
mk=models.CharField(max_length=10,primary_key=True)

私の検索ページのhtml:

{% extends "base.html" %}
{% block style %}
<link rel="stylesheet" type="text/css" href="/static/search_style.css" />
{% endblock %}
{% block java %}
<script type="text/javascript" src="/static/searches.js"></script>
{% endblock %}
{% block title %}Search{% endblock %}
{% block head %}Search{% endblock %}
{% block content %}
{% autoescape off %}
<div id="searches">
<form id="search" action="" method="get">
    <table border="0" cellpadding="0" cellspace="0">
        <tbody class="search">
            {% for form in formset.forms %}
            <tr>
                <td class="row">{{ form.row }}</td>
                <td class="query">{{ form.query }}</td>
                <td class="bool">{{ form.bools }}</td>
            </tr>
        {% endfor %}
        </tbody>
    </table>
    {{ formset.management_form }}
    <input type="submit" value="Submit" id="submit">
</form>
</div>
{% if formset.errors or errors %}
<div id="errors">
<h3>The following errors were encountered while trying to submit your search:</h3>
{% for x,y in formset.errors.items %}
<p>{{ x }} : {{ y }}</p>
{% endfor %}
{{ errors }}
</div>
{% endif %}
<div id="notes">
<p>Searching by dish names, locations, and restaurants is case-insensitive.</p>
<p>Searching by course uses  case-insensitive exact matching. Valid courses are Appetizer, Main, and Dessert.</p>
<p>Years should be entered YYYY. Five-year periods span either the first or second half of a decade, and should be entered YYYY-YYYY. Example valid five-year periods are 1900-1905, 1995-2000, etc.</p>
<p>Regular expression search follows MySQL regular expression syntax, as described <a href="http://dev.mysql.com/doc/refman/5.1/en/regexp.html" target="_blank">here</a>.</p>
 </div>

{% endautoescape %}
<br /><br /><br /><br /> <br /><br /><br />
{% endblock %}

{% block footer %}
<div id="warning">
<p>NOTE: This site and the information it contains are still in development. Some information may be missing or inaccurate.</p>
</div>
<div class="credits">
    Created and maintained by <a href="/about#sam">Sam Raker</a> and <a href="/about#rachel">Rachel Rakov</a>
    <br />
    Data graciously provided by <a href="http://menus.nypl.org" target="_blank">What's on the Menu?</a>
</div>
{% endblock %}
4

1 に答える 1

4

申し訳ありませんが、私の元の投稿は必要以上でした。明確にするために、あなたがする必要があるのは次のことだけです:

Q(year__icontains=year_input_variable) | Q(city__icontains=city_input_variable) & Q(name__icontains=name_input_variable)

& を and に使用 | または。

以前に投稿したのは、クエリに複数の単語が含まれている場合、演算子を使用してすべての単語が一致するかどうかを確認するためのものです。andまたは演算子を使用して単語のいずれかが一致した場合。または

于 2013-01-05T01:08:21.317 に答える