2014-10-29 63 views
5

我是Django新手,试图创建一个“搜索”形式为我的项目使用MySql与MyISAM引擎。到目前为止,我设法让表单起作用,但Django似乎并没有以相同的方式搜索所有字段。结果是随机的。例:虽然howtogetin似乎并不适用于region返回任何结果或description最坏的搜索工作正常..如何使用QuerySets和MySql“全文搜索”在多个字段中进行Django搜索?

这里是我的模型:

class Camp(models.Model): 
    owner = models.OneToOneField(User) 
    name = models.CharField(max_length=100) 
    description = models.TextField() 
    address1 = models.CharField(max_length=128) 
    address2 = models.CharField(max_length=128) 
    zipcode = models.CharField(max_length=128) 
    region = models.CharField(max_length=128) 
    country = models.CharField(max_length=128) 
    phone = models.CharField(max_length=60) 
    howtogetin = models.TextField() 

    def __str__(self): 
     return self.name 

这是我的观点:

def campsearch(request): 
if request.method == 'POST': 
    form = CampSearchForm(request.POST) 
    if form.is_valid(): 
     terms = form.cleaned_data['search'] 
     camps = Camp.objects.filter(
      Q(name__search=terms)| 
      Q(description__search=terms)| 
      Q(address1__search=terms)| 
      Q(address2__search=terms)| 
      Q(zipcode__search=terms)| 
      Q(region__search=terms)| 
      Q(country__search=terms)| 
      Q(howtogetin__search=terms) 
      ) 
     return render(request, 'campsearch.html', {'form':form, 'camps':camps}) 
else: 
    form = CampSearchForm() 
    return render(request, 'campsearch.html', {'form':form}) 

任何线索?

回答

7

我建议你实现这个:

#views.py 
def normalize_query(query_string, 
    findterms=re.compile(r'"([^"]+)"|(\S+)').findall, 
    normspace=re.compile(r'\s{2,}').sub): 

    ''' 
    Splits the query string in invidual keywords, getting rid of unecessary spaces and grouping quoted words together. 
    Example: 
    >>> normalize_query(' some random words "with quotes " and spaces') 
     ['some', 'random', 'words', 'with quotes', 'and', 'spaces'] 
    ''' 

    return [normspace(' ',(t[0] or t[1]).strip()) for t in findterms(query_string)] 

def get_query(query_string, search_fields): 

    ''' 
    Returns a query, that is a combination of Q objects. 
    That combination aims to search keywords within a model by testing the given search fields. 
    ''' 

    query = None # Query to search for every search term 
    terms = normalize_query(query_string) 
    for term in terms: 
     or_query = None # Query to search for a given term in each field 
     for field_name in search_fields: 
      q = Q(**{"%s__icontains" % field_name: term}) 
      if or_query is None: 
       or_query = q 
      else: 
       or_query = or_query | q 
     if query is None: 
      query = or_query 
     else: 
      query = query & or_query 
    return query 

并为每个搜索

#views.py 
def search_for_something(request): 
    query_string = '' 
    found_entries = None 
    if ('q' in request.GET) and request.GET['q'].strip(): 
     query_string = request.GET['q'] 
     entry_query = get_query(query_string, ['field1', 'field2', 'field3']) 
     found_entries = Model.objects.filter(entry_query).order_by('-something') 

    return render_to_response('app/template-result.html', 
      { 'query_string': query_string, 'found_entries': found_entries }, 
      context_instance=RequestContext(request) 
     ) 

而在模板

#template.html 
<form class="" method="get" action="{% url 'search_for_something' model.pk %}"> 
    <input name="q" id="id_q" type="text" class="form-control" placeholder="Search" /> 
    <button type="submit">Search</button> 
</form> 

#template-result.html 
{% if found_entries %} 
    {% for field in found_entries %} 
     {{ model.field }} 
    {% endfor %} 
{% endif %} 

和URL

#urls.py 
url(r'^results/$', 'app.views.search_for_something', name='search_for_something'), 
+1

我在互联网上看到过类似的东西,但我无法弄清楚它的工作方式。你测试过了吗?你能解释为什么它比Django的默认实现** **和**不包含**更好的实现吗? – adilbenseddik 2014-10-29 21:48:36

+1

嗨adilbenseddik,是的,我有它在我的项目,它很好。这种方法是由Julien Phalip在http://julienphalip.com/post/2825034077/adding-search-to-a-django-site-in-a-snap – 2014-10-29 21:53:59

+1

给我一试。 thx供参考。然而,你有什么不知道我的代码不工作吗?根据Django的文档,它应该工作得相当开箱。 – adilbenseddik 2014-10-29 22:12:14

1

__search只能使用带有全文索引的TextFields(听起来像您的描述字段是这样)。而不是这个尝试使用:

Q(name__icontains=terms) 

这是'CharField'字段不区分大小写'包含'。


搜索:https://docs.djangoproject.com/en/dev/ref/models/querysets/#search

icontains:https://docs.djangoproject.com/en/dev/ref/models/querysets/#icontains

+0

我同时使用,以延长使用'Q(name__search =计)的结果范围结束| Q(name__icontains =条款)',它做到了。但是,有些情况下结果是随机的。例如,如果_foo_和_foo2_在数据库中,则'_foo_ _foo2_'的搜索不起作用,而'_foo_ _和random string_'正常工作。一些搜索词似乎被忽略,即使它们与当前的“Q”情况相匹配。任何线索? – adilbenseddik 2014-10-29 21:39:34