Ajax url Problem mit Django

Django, Flask, Bottle, WSGI, CGI…
Metatron
User
Beiträge: 42
Registriert: Donnerstag 10. Mai 2018, 08:35

Ich versuche verzweifelt eingegebene Daten vom JavaScript zurück an Python zu schicken. Ich wollte dafür AJAX verwenden. (Erste frage wäre, sollte man dies dafür verwenden, oder gibt es etwas besseres?)
Das Problem ist glaube ich das, die Kommunikation nach dem Einloggen passieren soll und damit die Pfade von Django angepasst wurden, so das das Request nicht zu den Urls passt.

in der .js sieht der AJAX befehl wie folgt aus

Code: Alles auswählen

$.ajax({
                url:'bla',
                type: "POST",
                data: {stock : 42},
                success:function(response){},
                complete:function(){},
                error:function (xhr, textStatus, thrownError){}
            });
und in der ulrs.py steht:

Code: Alles auswählen

path(r'bla/', views.YourViewsHere, name='bla'),
Wenn ich das so durchführe, meldet mir der Server einen 404-Fehler, dass die Seite nicht gefunden werden kann, da sich der Benutzername im Pfad befindet.

Code: Alles auswählen

Not Found: /blub/Metatron/blub/bla
[21/Jan/2020 09:18:45] "POST /blub/Metatron/blub/bla HTTP/1.1" 404 3317

Deshalb habe ich die Ajax-URL um die App-Namen erweitert:

Code: Alles auswählen

$.ajax({
                    url:'blub:bla',
                    type: "POST",
                    data: {stock : 42},
                    success:function(response){},
                    complete:function(){},
                    error:function (xhr, textStatus, thrownError){}
                });
nun bekomme ich nichtmal in den Serverlogs angezeigt das überhaupt irgendetwas aufgerufen wird.

Die view.py sieht wie folgt aus:

Code: Alles auswählen

def YourViewsHere(request):
    print("bla")
    if request.method == 'GET':
        print("blub")
    elif request.method == 'POST':
        print(request.POST.get('data'))
Ich habe jetzt schon mehrere verschiedene tutorials erfolglos durchgearbeitet. Was mache ich falsch?
Benutzeravatar
sparrow
User
Beiträge: 4193
Registriert: Freitag 17. April 2009, 10:28

Ich habe schon eine Weile nichts mehr mit Django gemacht. Warum steht da ein Benutzername automatisch in der URL? Mein letzter Stand ist, dass der Benutzername in der Session vorgehalten wir - nicht in der URL.
Kann es sein, dass du auf /blub/Metatron/blub/ bist und von dort relativ die URL aufrufst?
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

blub:bla ist in URL-Syntax das Protokoll blub, das Dein Browser natürlich nicht kennt. Am einfachsten ist es, den absoluten Pfad anzugeben /bla oder /irgendwas/bla. Wie sieht denn Deine URL-Struktur aus? Aus welcher URL wird der Ajax-Aufruf abgesendet?

jquery ist heutzutage überflüssig. Für ajax gibt es modernere Methoden: https://developer.mozilla.org/en-US/doc ... sing_Fetch

`bla` ist keine gute URL und `YourViewsHere` ist ein ganz schlechter Funktionsname für eine URL, die ` bla` heißt.
Metatron
User
Beiträge: 42
Registriert: Donnerstag 10. Mai 2018, 08:35

Also ich verwende schon aussagekräftige Namen und Urls. Wenn es endlich läuft würde ich es anpassen.
Kann es sein, dass du auf /blub/Metatron/blub/ bist und von dort relativ die URL aufrufst?
hmm, ich mache es wie oben angegebene.

Die Ordnerstruktur sieht so aus:
  • Happy Ordner
    • blub Ordner
      • migration Ordner
        static Ordner
        • javascript.js
        template Ordner
        • blub Ordner
          • index.html
        admin.py
        apps.py
        models.py
        tests.py
        urls.py
        views.py
Benutzeravatar
sparrow
User
Beiträge: 4193
Registriert: Freitag 17. April 2009, 10:28

Was hat die URL auf der du dich befindest mit der Ordner- und Dateistruktur des Projektes zu tun?
Wenn du auf der URL http://example.com/asite bist und dort auf "anothersite" linkst, dann kommt da http://example.com/asite/anothersite heraus.
Ist dir der Unterschied zwischen relativen und absoluten URLS bewusst? Das hat nichts mit Python oder Django zu tun.

Wie lautete die URL, von der der Aufruf gesendet wird?
Metatron
User
Beiträge: 42
Registriert: Donnerstag 10. Mai 2018, 08:35

ich arbeite derzeit auf lokalhost.

der aufruf kommt von
http://127.0.0.1:8000/blub/Metatron/blub/
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

Und wie ist die URL zu bla? /bla oder/blub/bla oder /blub/Metatron/bla oder ganz anders?
Also, wie sieht die urls.py komplett aus, und wie ist diese urls.py in die globale eingebunden?
Die Lösung hab ich ja schon geschrieben, eine absolute URL zu benutzen. Ob das funktioniert, hast Du noch nicht beantwortet.
Metatron
User
Beiträge: 42
Registriert: Donnerstag 10. Mai 2018, 08:35

bla existiert selber nicht. Dies ist in den verschiedenen Tutorials auch so. Wenn ich das richtig verstehe soll ajax die information an die Adresse bla schicken. Django fängt diese Information, da sie in den urls angegeben ist und linkt sie weiter zu den views.py.

Eine feste Url funktioniert leider nicht, da auch hier der Benutzername im Weg steht. Für das Benutzernamen problem, hat django eigentlich die Statik Verknüpfung. Nur für den ajax aufruf weiß ich nicht wie ich das machen muss.
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Metatron: Was heisst 'bla' existiert nicht? Ich habe auch das Gefühl das Du absolute und relative URLs durcheinander bringst und vielleicht sogar Namen für Routen‽ Der Aufruf so wie Du ihn geschrieben hast, sendet die Informationen an die *relative* Adresse 'bla'. Welche das also am Ende tatsächlich ist, hängt davon ab an welcher Adresse Du Dich gerade befindest.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Metatron
User
Beiträge: 42
Registriert: Donnerstag 10. Mai 2018, 08:35

Ok nochmal ausführlich, so wie ich das verstanden habe und umgesetzt habe.


In dem Verzeichnis

Code: Alles auswählen

Happy/blub/template/blub/index.html
steht die html Datei die aufgerufen wird wenn sich ein User eingeloggt hat. In dieser Html Datei befindet sich der Script Aufruf des Javascriptes das hinter dem Verzeichnis:

Code: Alles auswählen

Happy/blub/static/javascript.js
steht In diesem js steht der Ajax Aufruf mit der url: bla.
Die Adresse bla selber existiert nicht.
In dem Verzeichnis:

Code: Alles auswählen

Happy/blub/urls.py 
steht der Befehl:

Code: Alles auswählen

path(r'bla/', views.YourViewsHere, name='bla'),
So wie ich das verstanden hab, wird hier eine path Weiterleitung angelegt, die den imaginären Pfad zu bla auf die views.py mit der entsprechenden Funktion weiterleitet.
Oder nicht?
Benutzeravatar
sparrow
User
Beiträge: 4193
Registriert: Freitag 17. April 2009, 10:28

Was wo in welcher Datei steht ist erst einmal untineressant. Vergiss das alles, das verwirrt dich nur.
Der Benutzername in der URL ist seltsam für dein Problem aber egal.

Du gibst im Browser eine URL ein oder klickst auf einen Link. Dann schickt der Browser eine Anfrage an eben diese URL und erwartet eine Antwort.
Wird ein AJAX-Request an einen Server geschickt, ist es das selbe in grün. Nur dass keine Seite sondern Daten zurück kommen

Hast du nun Django auf dem Server, stehen dort in der urls.py die verschiedenen URLs. In der Regel als regulärer Ausdruck. Trifft dieser reguläre Ausdruck zu, wird die dazugehörige Funktion ("view") aufgerufen und die Anfrage dorthin als Parameter übergeben.

Bis hierher ist es egal, ob du eine komplette Seite oder nur Daten für einen AJAX-Aufruf zurück gibst. Es ist immer dieser Ablauf.


So, der Unterschied zwischen relativen und absoluten URLS:
Verlinkst du von der URL http://www.example.de/seite/ per Link auf "test", dann verweist das auf http://www.example.de/seite/test. Nämlich relativ zu der Seite, von der du verlinkt hast.
Verlinkst du von der URL http://www.example.de/seite/ per Link auf "/test", dann verweist das auf http://www.example.de/test. Nämlich absolut von der entsprechenden Domain.


Wenn dir das nicht hilft, musst du dich noch einmal mit den Grundlagen von Webanwendungen beschäftigen.
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Metatron: In welchem Verzeichnis das Template oder die JavaScript-Datei liegt ist für die Frage hier nicht wirklich von Bedeutung. Es wurde ja bereits in einem früheren Beitrag schon mal angemerkt das die Verzeichnisstruktur nichts mit dem Problem zu tun hat.

Die Frage beim Ajax mit der URL "bla" ist zu welcher URL die denn relativ ist, denn mit "bla" alleine kann man nicht sagen zu welcher URL die Daten geschickt werden, man muss noch dazu sagen was denn die aktuelle URL ist. Die hat wie gesagt nichts mit der Verzeichnisstruktur des Projekts zu tun.

Die einzige Route die Du zeigst ist "bla/", da kann "bla" nicht zutreffen, weder relativ noch absolut, weil selbst wenn das Ajax von der Wurzel aus aufruft ist "bla" immer noch ungleich "bla/". (Oder entfernt Django automatisch abschliessende Slashes und versuchst's dann noch mal?)

"bla" ist eine relative URL und keine absolute URL. Die ist relativ zur aktuellen URL. Das ist ähnlich Dateisystemen: Wenn Du ``ls bla`` oder ``dir bla`` unter Unix oder Windows in eine Konsole eingibst, dann hängt es davon ab was das aktuelle Arbeitsverzeichnis ist, welches Verzeichnis da aufgelistet wird, oder ob es dort überhaupt ein "bla"-Unterverzeichnis gibt.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@Metatron: ich habe es ja schon geschrieben. Um zu verstehen, wie die URLs von Django aufgelöst werden, brauchen wir den Inhalt aller relevanter urls.py-Dateien, also die globale, die von Happy und die von blub. Nicht nur die eine Zeile mit bla, das hilft gar nichts.
Welche Route liefert die HTML-Seite aus, von der dann der Ajax-Request abgesendet wird?
Metatron
User
Beiträge: 42
Registriert: Donnerstag 10. Mai 2018, 08:35

Ah jetzt bin ich schlauer, vielen dank!
Ich hatte das schon richtig verstanden, nur nicht bedacht das die url in der Happy/urls.py aufgelöst wird.
Nachdem ich dort die url richtig eingetragen habe, kommt der Ajax aufruf auch an.

Nun bekomme ich aber einen fehler das der csrf Token fehlt.
also habe ich den Ajax aufruf geändert zu:

Code: Alles auswählen

    var token = '{{csrf_token}}';

     $.ajax({
        headers: { "X-CSRFToken": token },
        type: "POST",
        url: 'bla',
        data: {stock : i},
        success:function (response){},
        complete:function (){},
        error:function (xhr, textStatus, thrownError){}
     });
brachte aber noch keinen erfolg...
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Metatron: Ich dachte Du hast da eine *.js-Datei, die wird ja mit an Sicherheit grenzender Wahrscheinlichkeit nicht als Template verarbeitet sondern so wie sie ist ausgeliefert, also ist '{{csrf_token}}' eine Zeichenkette die genau das enthält was man da sieht und nicht auf magische Weise den Wert des CSRF-Tokens.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Du könntest dir den Wert auch aus dem Cookie holen: Cross Site Request Forgery protection - Ajax
Metatron
User
Beiträge: 42
Registriert: Donnerstag 10. Mai 2018, 08:35

ja, aber ich dachte das man {% %} verwenden kann, damit django beim erstellen der Seite den inhalt ersetzt.
also var token = "{% csrf_token %}"
und django ersetzt das {% csrf_token %} mit dem realen token...?
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Metatron: In Templates, ja, aber doch nicht auf magische Weise in jeder x-beliebigen Datei. Statische Sachen wie JavaScript-Dateien werden in Produktivsystemen doch auch üblicherweise gar nicht über Django ausgeliefert, sondern über einen Webserver.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Metatron
User
Beiträge: 42
Registriert: Donnerstag 10. Mai 2018, 08:35

Hallo,

ich habe die nächste Anfänger Frage.

Ich möchte eine Seite neu Rendern dafür nutze ich in der view.py den folgenden Rückgabewert:

Code: Alles auswählen

return render(request, '/water/WaterForm.html', {'WaterForm': WEsF})
Sofern ich einen HTML Butten im HTML Skript benutze, funktioniert das ganze auch ohne probleme.

Nun möchte ich jedoch, das ich etwas mit der Maus auf einer Javascript Karte anklicke und das dann die Seite neu gerendert wird.
Also den Button mit einer javascript interaktion ersetzen.

Ich habe dafür einen AJAX aufruf verwendet.

Code: Alles auswählen

            $.ajax(
            {
                headers: { "X-CSRFToken": token },
                type: "POST",
                url: 'water',
                data: {
                        'source[]': src,
                      },
                success:function (){},
                complete:function (){},
                error:function (xhr, textStatus, thrownError){}
            });
der AJAX aufruf kommt auch erfolgreich an, jedoch schaffe ich es nicht das die Seite neu gerendet wird. Ich nehme an das der AJAX aufruf von der Javascript Seite nach dem senden noch nicht abgeschlossen ist, oder?
Also das irgendetwas in den

Code: Alles auswählen

success:function (){},
ausgeführt werden muss? Die neu gerenderte Seite wird zum Javascript zurück gesendet oder?
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Metatron: Jain. Also ja, die ausgefüllte HTML-Vorlage wird zurückgesendet und ist in dem Argument enthalten das der `success`-Funktion übergeben wird, aber warum benutzt Du einen Ajax-Aufruf wenn doch eigentlich das passieren soll was ohne Ajax passieren würde?

Wenn Du das so machen willst, musst Du halt in der Funktion das Dokument welches im Browser angezeigt wird, durch das ersetzen was die `sucess`-Funktion bekommt.

`WEsF` ist übrigens ein denkbar schlechter Name. Der entspricht in der Schreibweise nicht den Konventionen und ist auch total unverständlich.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten