How can I do a Django search in multiple fields using QuerySets and MySql "Full Text Search"?

I'm starting a newbie Django trying to create a Search form for my project using MySql with the MyISAM engine. So far I have managed to get the form to work, but Django does not seem to search all the fields the same. The results are random. Example: searching in the region does not return the result or worse search in description works fine, but howtogetin doesn't seem to apply.

Here is my model:

 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 

Here is my view:

 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}) 

Any clue?

+5
source share
2 answers

I would recommend you implement this:

 #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 

And for every search

  #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) ) 

And in the template

 #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 %} 

And url

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

__ search will work only with TextFields with Full Text Indexing (sounds like your description field). Instead, try using:

 Q(name__icontains=terms) 

This is case-insensitive "contains" in the "CharField" fields.


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

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

+1
source

Source: https://habr.com/ru/post/1205793/


All Articles