Kann ich eine Ansicht aus einer anderen Ansicht heraus aufrufen?

73

Eine meiner Ansichten muss zusammen mit anderen Funktionen ein Element hinzufügen, aber ich habe bereits eine andere Ansicht, die speziell ein Element hinzufügt.

Kann ich so etwas machen wie:

def specific_add_item_view(request):
    item = Item.objects.create(foo=request.bar)

def big_view(request):
    # ...
    specific_add_item_view(request)
john2x
quelle
Ich denke, es ist einfacher zu verwenden: return spezifisch_add_item_view (Anfrage)
Roberth Solís

Antworten:

56

Ansichtsfunktionen sollten einen gerenderten HTML-Code (in einem HttpResponse) an den Browser zurückgeben . Das Aufrufen einer Ansicht innerhalb einer Ansicht bedeutet, dass Sie das Rendern (möglicherweise) zweimal ausführen. Berücksichtigen Sie stattdessen einfach das "Hinzufügen" in einer anderen Funktion, die keine Ansicht ist, und lassen Sie es von beiden Ansichten aufrufen.

def add_stuff(bar):
    item = Item.objects.create(foo=bar)
    return item

def specific_add_item_view(request):
    item = add_stuff(bar)
    ...

def big_view(request): 
    item = add_stuff(bar)
    ...
Seth
quelle
23
Was tun wir, wenn sich die aufgerufene Ansicht in einer Drittanbieter-App befindet?
Sandip Agarwal
1
Seth, wie man die Variable von view1 in der Vorlage aufruft oder wie man die Variable von view1 verwendet, um sie anzuzeigen
user2086641
Es gibt Fälle, in denen eine Ansicht eine andere Ansicht aufrufen soll, z. B. wenn Sie eine Ansicht zum Herunterladen einer Text- / CSV-Datei verwenden oder wenn Sie AJAX zum Aktualisieren eines Teils der Ansichtsvorlage verwenden (in diesem Fall wird die zweite Ansicht nicht direkt aufgerufen von der ersten Ansicht, sondern von einer jquery oder js in der HTML-Datei der Ansichtsvorlage)
Samwise Ganges
72

Sicher, solange alles gesagt und getan ist, gibt Ihre Ansicht ein HttpResponse-Objekt zurück. Folgendes ist vollständig gültig:

def view1(request):
    # do some stuff here
    return HttpResponse("some html here")

def view2(request):
    return view1(request)

Wenn Sie die HttpResponse nicht aus der ersten Ansicht zurückgeben möchten, speichern Sie sie einfach in einer Variablen, die Sie ignorieren möchten:

def view1(request):
    # do some stuff here
    return HttpResponse("some html here")

def view2(request):
    response = view1(request)
    # do some stuff here
    return HttpResponse("some different html here")
Brady
quelle
Nur um zu verdeutlichen, was Sie tun: Im zweiten Beispiel starten Sie nur eine Logik in view1 und tun nichts mit den Antwortobjekten, oder?
Dominique Guardiola
5
Ja das ist die Idee. view1arbeitet wahrscheinlich an einem Objekt eines Modells oder etwas. Seth hat jedoch die richtige Idee. Es ist wahrscheinlich am besten , die gemeinsame Funktionalität aus beiden Ansichten zu nehmen und es in eine Funktion setzen , dass view1und view2Call- und dann kehren sie ihre jeweiligen Httpresponse - Objekte. Es ist nicht erforderlich, eine HttpResponse zu generieren, die nicht verwendet wird - insbesondere, wenn diese eine Vorlage enthält, die viele Abfragen erfordert.
Brady
@ Brady, wie man die Variable von view1 in der Vorlage aufruft oder wie man die Variable von view1 verwendet, um anzuzeigen
user2086641
3
Obwohl Seth die richtige Idee hat, ist Ihre Lösung der richtige Weg, wenn Sie eine Ansicht von einer Drittanbieter-App aus aufrufen müssen!
Diego Ponciano
1
Das zweite Muster ist schlecht. Sie können gelegentlich view1 von view2 aus aufrufen. In diesem Fall sollte jedoch nur view1 zurückgegeben werden . Der Punkt ist, dass Sie einige zusätzliche Parameter an view1 übergeben, die normalerweise nicht von der URL abgerufen werden (extra_context, template, success_url, ...). Hier fungiert view2 als Proxy-Ansicht für view1. Das ist so ziemlich nur ein zulässiges Muster, wenn Sie die gesamte Logik von view1 benötigen (andernfalls sollte die Logikextraktion verwendet werden). Ab der dritten App sollten Sie nur eine Ansicht erstellen und sie vollständig neu schreiben, wenn Sie eine Änderung benötigen. Bei klassenbasierten Ansichten verwenden Sie in solchen Fällen die Vererbung, damit sie sauberer ist.
Klima
9

Ein besserer Weg ist die Verwendung des Vorlagensystems. Ideen von @Seth und @brady kombinieren:

def specific_add_item_view(request, extra_context_stuff=None):
    Item.objects.create()
    context_variables = {} # obviously want to populate this
    if extra_context_stuff:
        context_variables.update(extra_context_stuff)
    return render(request, 'app_name/view1_template.html', context_variables)

def bigger_view(request):
    extra_context_stuff = {'big_view': True}
    return specific_add_item_view(request, extra_context_stuff)

Und Ihre app_name / view1_template.html enthält möglicherweise ein bedingtes Vorlagen-Tag

{% if big_view %}
<p>Extra html for the bigger view</p>
{% endif %}
Kochfelder
quelle
Vielen Dank an @Neceros für den Hinweis, dass die neuesten Django-Versionen render_to_responsezugunsten von render.
Kochfelder
0

Ohne klassenbasierte Ansichten:

def my_view(request):
    return call_another_view(request)

def call_another_view(request):
    return HttpResponse( ... )

Mit klassenbasierten Ansichten :

def my_view(request):
    return CallAnotherView.as_view()(request)

class CallAnotherView(View):
    ...
Guilherme IA
quelle