Suchfunktion in Django

Django, Flask, Bottle, WSGI, CGI…
Antworten
Gelo
User
Beiträge: 8
Registriert: Sonntag 3. Dezember 2017, 15:01

Hallo zusammen,

ich bekomme meine Suchfunktion in Django einfach nicht zum laufen und ich habe keine Ahnung warum.
Ich habe eine kleine Seite für Musik erstellt. Dort sind Alben aufgelistet und ich möchte einfach nur nach dem Album-Titel suchen.

[codebox=html5 file=base.html]

<form class="navbar-form navbar-left" role="search" method="get" action=".">
<div class="form-group">
<input type="text" class="form-control" name="q" value="{{request.GET.q}}" >
</div>
<button type="submit" class="btn btn-default">Search</button>
</form>

[/code]

Code: Alles auswählen


from django.db.models import Q

def search(request):
  template = 'Alben/albumauswahl.html'
  query = request.GET.get('q')
  results = Album.objects.filter(Q(album_titel__icontains=query))
  return render (request, template, results)

Fehlermeldungen kommen keine, im Link wird angezeigt, dass er sucht, aber es verändert sich an der Seite nichts.
Was mache ich falsch?

Vielen Dank im Voraus.
Benutzeravatar
noisefloor
User
Beiträge: 3829
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

... und willkommen im Forum :-)

Grundsätzlich ist es hilfreich, wenn du _allen_ relevanten Code zeigst. Beim View fehlt definitiv was - so wie gezeigt wäre `Album` nicht definiert.

Bei `render` ist eine Fehler drin: `result` sollte ein Dict sein, damit du im Template über den Schlüssel auf den Wert zugreifen kannst.
Im gezeigten Template gibt es auch keine Teil, der ein mögliches Ergebnis anzeigen würde... Du hast lediglich das Suchforumular drin.
Der Sinn von `value="{{request.GET.q}}"` erschließt sich mir nicht - was willst du damit erreichen?

Das Q Object brauchst du bei dieser Suche nicht, weil du nur in einem Feld suchst. `results = Album.objects.filter(album_titel__icontains=query)` sollte dir das gleiche Ergebnis zurück liefern.

Gruß, noisefloor
Gelo
User
Beiträge: 8
Registriert: Sonntag 3. Dezember 2017, 15:01

Hallo noisefloor,
vielen Dank für deine Antwort.
Du hast Recht in Views.py fehlt noch: from .models import Album. Das hatte ich vergessen hier dazu zu schreiben, ist aber vorhanden.

Was `value="{{request.GET.q}}"` betrifft, bin ich mir selbst unschlüssig. Ich habe das nach einem Tutorial versucht umzusetzen, dort wurde erwähnt, dass das benötigt wird, um den gesuchten Text in der Such-Box anzuzeigen. Ich weiß leider auch überhaupt nicht, was ich dort anderes reinschreiben soll.

Tut mir leid, aber ich stehe etwas auf dem Schlauch.

Bei Ausgabe fehlt mir also so ein Return, sowas hier:

Code: Alles auswählen


 return {
       
     'results' : album_titel,
    }


Benutzeravatar
noisefloor
User
Beiträge: 3829
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Ich habe das nach einem Tutorial versucht umzusetzen, dort wurde erwähnt, dass das benötigt wird, um den gesuchten Text in der Such-Box anzuzeigen. Ich weiß leider auch überhaupt nicht, was ich dort anderes reinschreiben soll.
axo... ja, kann man machen, wobei das IMHO nicht das "typische" Verhalten einer Webseite ist. Ich würde eher erwarten, dass dann unter der Suchmaske eine Liste von Treffern kommt.
Bei Ausgabe fehlt mir also so ein Return, sowas hier:
Nee, eher so was:

Code: Alles auswählen

results = Album.objects.filter(album_titel__icontains=query)
context = {'search_result':result}
return render (request, template, context)
BTW: welches Tutorial hast du bis dato gelesen? Richtig gut sind das offizielle Django-Tutorial und das "Django for Girls" Tutorial. Letzteres ist auch für Boys geeignet ;-)

Gruß, noisefloor
Benutzeravatar
noisefloor
User
Beiträge: 3829
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

hier mal ein minimales Beispiel für Django 1.11, dass das macht, was du suchst:

urls.py:

Code: Alles auswählen

from django.conf.urls import url
from . import views

app_name = 'albumsearch'

urlpatterns = [
url(r'^$', views.index, name='index')
]
models.py:

Code: Alles auswählen

from django.db import models

class Album(models.Model):
    title = models.CharField(max_length=50)
    artist = models.CharField(max_length=50)
views.py:

Code: Alles auswählen

from django.shortcuts import render
from .models import Album

def index(request):
    if request.method == 'GET':
        return render(request, 'albumsearch/search.html')
    if request.method == 'POST':
        search_term = request.POST['term']
        results = Album.objects.filter(title__icontains=search_term)
        if not results:
            results = ['no match found']
        context = {'results': results,
                   'searchterm': search_term}
        return render(request, 'albumsearch/search.html', context)
das Template `search.html':
[codebox=html5 file=Unbenannt.html]<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Django Album Search</title>
</head>
<body>
<form action="{% url 'albumsearch:index' %}" method="POST">
{% csrf_token %}
<input type="text" name="term"
{% if searchterm %}
value="{{ searchterm }}"
{% endif %}>
<input type="submit" value="Search">
</form>
{% if results %}
<hr/>
<ul>
{% for result in results %}
<li>"{{ result.title }}" by {{ result.artist }}
{% endfor %}
</ul>
{% endif %}
</body>
</html>[/code]

Wie gesagt, minimalistisch, ohne Fehlerbehandlung, ohne Einsatz des Form-Frameworks etc.

Gruß, noisefloor
Gelo
User
Beiträge: 8
Registriert: Sonntag 3. Dezember 2017, 15:01

Vielen vielen Dank!

Leider läuft es immer noch nicht. Nun bleibt die Seite weiß und die Fehlermeldung: "METHOD NOT ALLOWED (POST)"

Ich habe versucht, dein Beispiel in meine Anwendung zu integrieren:

Ich habe nur eine Seite, wo sich alles abspielt. Und ich habe nur zwei html-Seiten. Nämlich base, wo alles grafische drin ist, so auch der Suche-Button und Index, welches die Alben-Titel darstellt.

Also habe ich die Suchebutton hier drin und nun an deinem Beispiel angepasst:

[codebox=html5 file=base.html]
...

<form class="navbar-form navbar-left" role="search" method="POST" action="{% url 'Alben:index' %}">

<div class="form-group">
{% csrf_token %}
<input type="text" class="form-control" name="term"
{% if searchterm %}
value="{{ searchterm }}"
{% endif %}>

</div>
<button type="submit" class="btn btn-default">Suchen</button>
</form>
{% if results %}
<hr/>
<ul>
{% for result in results %}
<li>"{{ result.album_titel }}"
{% endfor %}
</ul>
{% endif %}
....

[/code]

Code: Alles auswählen

from .models import Album
from django.shortcuts import render


def search(request):
    if request.method == 'GET':
        return render(request, 'Alben/index.html')
    if request.method == 'POST':
        search_term = request.POST['term']
        results = Album.objects.filter(album_titel__icontains=search_term)
        if not results:
            results = ['no match found']
        context = {'results': results,
                   'searchterm': search_term}
        return render(request, 'Alben/index.html', context)




Code: Alles auswählen


from django.conf.urls import url
from . import views

app_name = "Alben"


urlpatterns = [

    url(r'^$', views.IndexView.as_view(), name='index'),
  
]

Was mache ich nun falsch?
Benutzeravatar
noisefloor
User
Beiträge: 3829
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

deine `urls.py` ist falsch. Das Pattern, dass du angibst, ist für einen Class-Based View - wir benutzen aber hier eine Function-based View.

Guck' dir mal meine `urls.py` an, da ist es korrekt. Man könnte das auch über ein CBV machen - aber da du in deinem Ausgangspost auch einen FBV hattest, habe ich den auch genommen. Was hier IMHO auch i.O. ist.

Gruß, noisefloor
Gelo
User
Beiträge: 8
Registriert: Sonntag 3. Dezember 2017, 15:01

Nochmals danke für deine Antwort.

Ich habe eine alte Version hervor geholt, wo noch in der views.py alles mit def war und noch ohne class.
Dementsprechend auch mit den alten URL's:

Code: Alles auswählen


 url(r'^$', views.index, name='index'),

Da habe ich jetzt keine Fehlermeldung. Doch wenn ich in die Suche, was eingebe, passiert nichts. Ich bin langsam am verzweifeln.
Benutzeravatar
noisefloor
User
Beiträge: 3829
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

"nichts" heißt...? Wird wirklich nichts gezeigt oder erscheint "no result found"? Wenn nie irgendwas erscheint, dann spricht das stark dafür, dass du nur GET-Requests sendest.

Bau' dir doch mal ein paar print-Anweisungen zwecks Debugging in den Code ein. Z.B., um dir per print das Ergebnis der Suche in der Konsole ausgeben zu lassen.

Der von mir gepostete Code läuft definitiv unter Django 1.11 (das ist die aktuelle LTS Version), habe ich getestet. Welche Django-Version nutzt du?

Gruß, noisefloor
Gelo
User
Beiträge: 8
Registriert: Sonntag 3. Dezember 2017, 15:01

Guten Morgen.
Ja, es tut sich nichts. Die Seite aktualisiert, aber bleibt genauso so bestehen. Es zeigt mir nach wie vor alle Alben Titel an.
Ich nutze ebenfalls Django 1.11.
Gelo
User
Beiträge: 8
Registriert: Sonntag 3. Dezember 2017, 15:01

Ich habe jetzt nochmal ein bisschen hin und her probiert:
Ich habe deinen HTML-Code vollständig übernommen und gegen meinen ersetzt. Weil ich vielleicht dachte, dass irgendwas mit der Anzeige nicht stimmt. Doch es bleibt unverändert. Dann habe ich den HTML-Code aus der base.html in die index.html geschoben, auch das blieb unverändert.
Also, wenn ich einen Titel eingebe, dann lädt die Seite neu und alle Alben stehen noch genauso da, wie vorher.
Wenn ich in die Commandline gucke, dann steht da auch "POST/Alben/HTTP ... " also, ruft er ja die Funktion auch auf.
Ist mir alles ein ziemliches Rätsel.
Benutzeravatar
noisefloor
User
Beiträge: 3829
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

wieso stehen dann _alle_ Alben da? Das passiert nur, wenn das Suchfeld leer ist.

Poste bitte mal deinen _vollständigen_ Code: views.py, models.py, urls.py, alle relevanten Templates.

Gruß, noisefloor
Benutzeravatar
noisefloor
User
Beiträge: 3829
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

welches Ergebnis liefert der Query denn, wenn du ihn in der Django-Shell aufrufst? Wird die Suche da richtig ausgeführt?

Gruß, noisefloor
Gelo
User
Beiträge: 8
Registriert: Sonntag 3. Dezember 2017, 15:01

Hallo,

wenn ich über die Shell Album.objects.filter(album_titel__icontains='Summer') eingebe, dann findet er auch Summer.
Benutzeravatar
noisefloor
User
Beiträge: 3829
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

gut. Dann musst du jetzt raus finden, ob der Teil `if request.method=='POST'` überhaupt ausgeführt wird. Z.B. indem du hinter die Zeile `results=...` eine Zeile `print(results)` einbaust. Damit solltest du im Terminal eine Ausgabe sehen (selbst, wenn die Suche kein Ergebnis hat).

Wenn nein weißt du, dass nie ein POST-Request ausgeführt wird -> Fehler im Template.

Wenn ja weißt du, dass die Daten entweder falsch / nicht ans Template übergeben werden oder im Template nicht korrekt verarbeitet werden.

Gruß, noisefloor
Gelo
User
Beiträge: 8
Registriert: Sonntag 3. Dezember 2017, 15:01

Vielen Dank für deine Unterstützung.
Ich werde mal ein wenig rumprobieren.
Benutzeravatar
noisefloor
User
Beiträge: 3829
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

na ja, probieren ist schlecht - Programmieren ist ja nicht raten. Du musst schon versuchen, den Fehler systematisch einzukreisen.

Welche Django-Version verwendest du eigentlich?

Gruß, noisefloor
Antworten