2014-10-29 7 views
5

Ich bin ein Django Anfänger, versucht, ein "Suche" Formular für mein Projekt mit MySql mit MyISAM-Engine zu erstellen. Bisher gelang es mir, das Formular zur Arbeit zu bringen, aber Django scheint nicht alle Felder auf die gleiche Weise zu durchsuchen. Die Ergebnisse sind zufällig. Exemple: Suche in region kehrt kein Ergebnis oder schlechteste Suche in description gut funktioniert, während howtogetin nicht anzuwenden scheinen ..Wie kann ich Django mit QuerySets und MySql "Volltextsuche" in mehreren Feldern suchen lassen?

Hier mein Modell ist:

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 

Hier ist meine Ansicht:

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

Irgendwelche Hinweise?

Antwort

7

Ich würde Ihnen empfehlen, dies zu implementieren:

#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 

Und für jede Suche

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

Und in der Vorlage

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

und die URL

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

Ich habe so etwas im Internet gesehen, aber ich kann nicht wirklich herausfinden, wie es funktioniert. Hast du es getestet? Kannst du erklären, warum es eine bessere Implementierung ist als Djangos Standardimplementierung für ** search ** und ** incontains **? – adilbenseddik

+1

Hi adilbenseddik, ja ich habe es in meinem Projekt und es funktioniert super. Dieser Ansatz wurde von Julien Phalip in http://julienphalip.com/post/2825034077/adding-search-to-a-django-site-in-a-snap –

+1

Ich werde es versuchen. Danke für die Referenz. Hast du eine Ahnung, was nicht mit meinem Code funktioniert? es sollte nach der Dokumentation von Django recht gut funktionieren. – adilbenseddik

1

__search funktioniert nur bei TextFields mit Volltextindizierung (klingt wie Ihr Beschreibungsfeld ist dies). Statt dessen versuchen, mit:

Q(name__icontains=terms) 

Das ist ein Fall unempfindlich ‚enthält‘ auf ‚CharField‘ Felder aus.


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

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

+0

ich sowohl den Ergebnisbereich mit 'Q erweitern endete mit (name__search = Begriffe) | Q (name__icontains = Begriffe)' und es tat. Es gibt jedoch Fälle, in denen Ergebnisse zufällig sind. wenn zum Beispiel _foo_ und _foo2_ in der Datenbank sind, funktioniert die Suche nach '_foo_ _foo2_' nicht, während '_foo_ _and random string_' gut funktioniert. Einige Suchbegriffe scheinen ignoriert zu werden, selbst wenn sie mit einem vorhandenen 'Q'-Fall übereinstimmen. irgendeine Ahnung? – adilbenseddik