Django: Wie leite ich einen Beitrag um und gebe die Beitragsdaten weiter?

79

Wenn ich eine POST-Anfrage in der Datei Django views.py verarbeite, muss ich sie manchmal auf eine andere URL umleiten. Diese URL, zu der ich umleitung, wird von einer anderen Funktion in derselben Django views.py-Datei verarbeitet. Gibt es eine Möglichkeit, dies zu tun und die ursprünglichen POST-Daten beizubehalten?

UPDATE: Weitere Erklärungen, warum ich das tun möchte. Ich habe zwei Web-Apps (nennen wir sie AppA und AppB), die vom Benutzer in ein Textfeld eingegebene Daten akzeptieren. Wenn der Benutzer auf Senden klickt, werden die Daten verarbeitet und detaillierte Ergebnisse angezeigt. AppA und AppB erwarten unterschiedliche Datentypen. Manchmal sendet ein Benutzer fälschlicherweise Daten vom Typ AppB an AppA. In diesem Fall möchte ich sie zu AppB umleiten und die AppB-Ergebnisse anzeigen oder zumindest mit den Daten füllen lassen, die sie in AppA eingegeben haben.

Ebenfalls:

  • Der Client möchte zwei separate Apps, anstatt sie zu nur einer zu kombinieren.

  • Ich kann den Code nicht anzeigen, da er einem Client gehört.

UPDATE 2: Ich habe entschieden, dass KISS hier das beste Prinzip ist. Ich habe die beiden Apps zu einer zusammengefasst, was die Dinge einfacher und robuster macht. Ich sollte in der Lage sein, den Kunden davon zu überzeugen, dass dies auch der beste Weg ist. Vielen Dank für das tolle Feedback. Wenn ich zwei Apps wie beschrieben warten würde, wären Sitzungen meiner Meinung nach der richtige Weg, dies zu tun - danke an Matthew J Morrison, der dies vorgeschlagen hat. Dank Dzida als seine Kommentare haben mich über das Design und die Vereinfachung nachgedacht.

FunLovinCoder
quelle
Müssen Sie wirklich eine Weiterleitung an den Client senden, oder können Sie dies tun, indem Sie einfach eine Funktion aufrufen und alle Post-Daten an diesen übergeben?
Matthew J Morrison
Ich muss die URL im Browser des Clients ändern, daher ist dies die einzige Möglichkeit, dies zu tun.
FunLovinCoder
und Sie können nicht einfach die gesamte Verarbeitung mit den Post-Daten zuerst durchführen und dann nachträglich umleiten?
Matthew J Morrison
Ich habe eine ähnliche Situation, aber die POST-Daten stimmen entweder mit den vorhandenen Daten überein oder nicht. Wenn es übereinstimmt, erhalte ich die ID für diese Daten und übergebe diese ID über die Variable GET in der Umleitung an das Skript. Ich speichere auch die POST-Daten in SESSION. Jetzt lädt die umgeleitete Seite die Daten, auf die idin GET verwiesen wird , und hat auch Zugriff auf andere von POST übermittelte Daten.
Buttle Butkus

Antworten:

55

Wenn Sie mit einem solchen Problem konfrontiert sind, besteht eine geringe Wahrscheinlichkeit, dass Sie Ihre Entwürfe überarbeiten müssen.

Dies ist eine Einschränkung von HTTP, die POST-Daten nicht mit Weiterleitungen verbinden können.

Können Sie beschreiben, was Sie erreichen wollen, und vielleicht können wir dann über eine ordentliche Lösung nachdenken.

Wenn Sie keine Sitzungen verwenden möchten, wie von Matthew vorgeschlagen, können Sie POST-Parameter in GET an die neue Seite übergeben (beachten Sie einige Einschränkungen wie die Sicherheit und die maximale Länge der GET-Parameter in der Abfragezeichenfolge).

UPDATE zu Ihrem Update :) Es klingt seltsam für mich, dass Sie 2 Web-Apps haben und diese Apps eine views.py verwenden (habe ich recht?). Überlegen Sie auf jeden Fall, ob Sie Ihre Daten von POST in GET an die richtige Ansicht übergeben möchten (falls die Daten natürlich nicht vertraulich sind).

dzida
quelle
2
Ich kann sehen, was er versucht, könnte gültig sein, wenn er versucht, eine abgelaufene Anmeldung zu verarbeiten, die einen Benutzer nach dem Absenden eines Formulars zur Anmeldung zwingt. In diesem Fall möchte er die Anmeldung beibehalten Daten, die übermittelt wurden und den Benutzer nicht zwingen, alles erneut einzugeben, nachdem er den Anmeldebildschirm abgeschlossen hat.
Matthew J Morrison
Ich bin mir nicht sicher, ob ich den Punkt verstanden habe, aber in diesem Fall kann der Anmeldevorgang in der ersten Ansicht mit geringen Codeänderungen und ohne unnötige Weiterleitungen ausgeführt werden. Es wäre großartig, vorhandenen Code zu lesen, um genauere Ratschläge zu erhalten.
Dzida
Ich sage, wenn Sie ein Formular senden und nicht angemeldet sind, werden Sie zu einem Anmeldeformular weitergeleitet. In diesem Szenario verlieren Sie alles, was Sie gesendet haben. Ich bin damit einverstanden, dass vorhandener Code angezeigt werden kann.
Matthew J Morrison
1
Es liegt nicht an Ihnen, zu entscheiden, ob der Anwendungsfall gültig ist oder nicht. Ich bin mit der gleichen Situation konfrontiert, für die eine Weiterleitung mit frischem POST die perfekte Lösung in Bezug auf Einfachheit und Modularität ist.
Rabih Kodeih
54

Ich denke, wie ich mit dieser Situation wahrscheinlich umgehen würde, wäre, die Post-Daten in der Sitzung zu speichern und sie dann zu entfernen, wenn ich sie nicht mehr benötige. Auf diese Weise kann ich nach einer Weiterleitung auf die ursprünglichen Postdaten zugreifen, obwohl dieser Post weg ist.

Funktioniert das für das, was Sie versuchen zu tun?

Hier ist ein Codebeispiel dessen, was ich vorschlage: (Denken Sie daran, dass dies ungetesteter Code ist.)

def some_view(request):
    #do some stuff
    request.session['_old_post'] = request.POST
    return HttpResponseRedirect('next_view')

def next_view(request):
    old_post = request.session.get('_old_post')
    #do some stuff using old_post

Eine andere Sache, die Sie beachten sollten ... Wenn Sie dies tun und auch Dateien hochladen, würde ich es nicht so machen.

Matthew J Morrison
quelle
1
Ich habe noch nie Sitzungen verwendet, aber ich werde mir das ansehen, danke.
FunLovinCoder
1
Dies ist nicht die beste Vorgehensweise, hilft aber dennoch. Ich denke, für diese Ausgabe werden wir nichts Schöneres bekommen.
Guilherme David da Costa
@GuilhermeDaviddaCosta warum sagst du, dass es nicht die beste Praxis ist? Können Sie uns einen Hinweis geben?
Buttle Butkus
weil es keine gute Idee ist, zu viele Daten in einer Sitzung zu speichern. Aber wie gesagt, ich kann mir nichts Schöneres vorstellen.
Guilherme David da Costa
4
Nun, das hängt davon ab, wo Sie Ihre Sitzung speichern. In letzter Zeit habe ich Leute gesehen, die bei jeder Anfrage einen ganzen Server mit Memcached für Sitzungen und Lastausgleich (mit Round Robin) verwendet haben. Ich möchte Ihnen keine Ratschläge geben, für die ich nicht eintreten kann, aber ich würde die Datei als temporär speichern und nur einen Link dafür in der Sitzung erhalten. Scheint, als würde heutzutage niemandem der Widder ausgehen.
Guilherme David da Costa
23

Sie müssen eine temporäre HTTP 1.1-Umleitung (307) verwenden.

Leider geben Django redirect()und HTTPResponseRedirect (permanent) nur 301 oder 302 zurück. Sie müssen es selbst implementieren:

from django.http import HttpResponse, iri_to_uri
class HttpResponseTemporaryRedirect(HttpResponse):
    status_code = 307

    def __init__(self, redirect_to):
        HttpResponse.__init__(self)
        self['Location'] = iri_to_uri(redirect_to)

Siehe auch das Modul django.http .

Bearbeiten:

Ändern Sie iri_to_uriin den neuesten Django-Versionen den Import in:

from django.utils.encoding import iri_to_uri
Lloeki
quelle
Neuere Versionen von Django haben eine permanente Weiterleitung HttpResponsePermanentRedirect, sind sich jedoch nicht sicher, ob sie das ursprüngliche Problem löst. Docs.djangoproject.com/de/dev/ref/request-response/…
JiminyCricket
9

Verwenden Sie requestspackage.Its sehr einfach zu implementieren

pip install requests

Dann können Sie beliebige URLs mit einer beliebigen Methode aufrufen und Daten übertragen

Importieren Sie in Ihren Ansichten Anfragen

import requests

Um Daten zu veröffentlichen, folgen Sie dem Format

r = requests.post('http://yourdomain/path/', data = {'key':'value'})

Verwenden Sie, um die absolute URL in der Django-Ansicht zu erhalten

request.build_absolute_uri(reverse('view_name'))

So sieht der Django-Ansichtscode aus

r = requests.post(
            request.build_absolute_uri(reverse('view_name')), 
            data = {'key':'value'}
    )

Wo rist das Antwortobjekt mit status_codeund contentAttribut. r.status_codegibt den Statuscode an (bei Erfolg sind es 200) und r.contentgibt den Antworttext an. Es gibt eine json-Methode ( r.json()), die die Antwort in das json-Format konvertiert

Anfragen

request.post

Aneesh RS
quelle
4

Rufen Sie einfach Ihre neue Ansicht aus Ihrer alten Ansicht mit demselben Anforderungsobjekt auf. Natürlich führt dies nicht zu einer Umleitung als solche, aber wenn Sie nur Daten von einer Ansicht in die andere übertragen möchten, sollte dies funktionieren.
Ich habe das folgende Snippet getestet und es funktioniert.

from django.views.generic import View

class MyOldView(View):
    def post(self, request):
        return MyNewView().post(request)

class MyNewView(View):
    def post(self, request):
        my_data = request.body
        print "look Ma; my data made it over here:", my_data
Komu
quelle
1
Ich habe diese Lösung verwendet und sie funktionierte ohne Probleme.
Guival
1

Sie können damit Rendering und Kontext verwenden :

Render(request,"your template path",        {'vad name' : var value}

Sie können Vars in der Vorlage empfangen:

{% If var name %}
 {{ var name }}
{% endif %}
Omid reza
quelle
1

Ich hatte kürzlich ein ähnliches Problem.

Grundsätzlich hatte ich ein Formular A, nach dem Absenden wurde ein anderes Formular B angezeigt, das einige Ergebnisse + ein Formular enthält. Beim Senden von B wollte ich dem Benutzer eine Warnung anzeigen und den Benutzer nur auf B halten.

Ich habe dies gelöst, indem ich die Ergebnisse in einem <output>Feld in B angezeigt habe.

<output name="xyz" value="xyz">{{xyz}}</output>

Und ich habe die gleiche Ansicht für A-> B und B-> B verwendet. Jetzt musste ich nur noch unterscheiden, ob die Anfrage von A oder B kommt und entsprechend rendern.

def view1(request):
    if "xyz" in request.POST:
        # request from B
        # do some processing
        return render(request, 'page.html', {"xyz":request.POST["xyz"]})
    else:
        # request from A
        res = foo() # some random function
        return render(request, 'page.html', {"xyz":res})

Dies funktioniert jedoch nur, wenn Form B klein und nicht so dynamisch ist.

rkp768
quelle
0

Wenn Sie nach der Verarbeitung des POST eine Umleitung verwenden AppB, können Sie die AppBMethode tatsächlich von der Methode aus aufrufen AppA.

Ein Beispiel:

def is_appa_request(request):
    ## do some magic.
    return False or True
is_appb_request = is_appa_request

def AppA(request):
    if is_appb_request(request):
       return AppB(request)
    ## Process AppA.
    return HttpResponseRedirect('/appa/thank_you/')

def AppB(request):
    if is_appa_request(request):
       return AppA(request)
    ## Process AppB.
    return HttpResponseRedirect('/appb/thank_you/')

Dies sollte eine transparente Erfahrung für den Endbenutzer ergeben, und der Kunde, der Sie eingestellt hat, wird den Unterschied wahrscheinlich nie erfahren.

Wenn Sie nach dem POST nicht umleiten, sind Sie dann nicht besorgt über doppelte Daten, weil der Benutzer die Seite aktualisiert?

Jack M.
quelle
Es wäre großartig, wenn eine einfache Lösung wie diese funktionieren würde. Nach der Verarbeitung der Daten muss ich jedoch detaillierte Ergebnisse anzeigen. Dies würde Sitzungen erfordern (wie von Matthew J Morrison vorgeschlagen), nicht wahr?
FunLovinCoder
1
Sie können dies auf drei Arten tun. # 1, speichern Sie die Daten in der Datenbank und übergeben Sie pkden neuen Eintrag, wenn Sie umleiten. # 2, speichern Sie die Daten im cacheBackend und übergeben Sie den Schlüssel erneut. # 3, speichern Sie es in der Sitzung. All dies ist für eine Web-App völlig normal, auch wenn es nur vorübergehend ist. Wenn die zu analysierenden Formulardaten nicht trivial sind, würde dies das System auch schneller machen, wenn die Ausgabe bereits zwischengespeichert wäre.
Jack M.