Django return redirect () z parametrami

83

W mojej funkcji widoku chcę wywołać inny widok i przekazać do niego dane:

return redirect('some-view-name', backend, form.cleaned_data)

, gdzie backend jest obiektem registration.backends, a form.cleaned_data jest dyktatem danych formularza (ale oba muszą być wysłane jako * args lub ** kwargs, aby zapobiec zgłaszaniu Don't mix *args and **kwargs in call to reverse()!błędów). Z tego, co znalazłem w dokumentach:

def my_view(request):
    ...
    return redirect('some-view-name', foo='bar')

Wygląda na to, że muszę podać argument „nazwa-widoku”, ale czy jest to tylko nazwa funkcji widoku, czy nazwa adresu URL? Chciałbym więc zrobić to podobnie do sposobu, w jaki jest to robione w rejestracji django, gdzie:

to, args, kwargs = backend.post_registration_redirect(request, new_user)
return redirect(to, *args, **kwargs)

def post_registration_redirect(self, request, user):
    return ('registration_complete', (), {})

OK, czy mogę teraz bezpośrednio wywołać moją funkcję widoku, czy też muszę podać jej adres URL? A co ważniejsze, jak powinno wyglądać moje wywołanie funkcji (i adres URL w razie potrzeby)? Zarówno zaplecze, jak i clean_data są przekazywane przez ten widok do późniejszego użycia. Próbowałem tego, ale jest to niewłaściwe:

url(r'^link/$', some-view-name)   
def some-view-name(request, *args):

Tak dobrze jak to :

return redirect('some_url', backend=backend, dataform.cleaned_data) 
url(r'^link/$', some-view-name)    
def some-view-name(request, backend, data):

nadal NoReverseMatch. Ale w rejestracji django widziałem coś takiego:

url(r'^register/$',register,{'backend': 'registration.backends.default.DefaultBackend'}, name='registration_register'),

def register(request, backend, success_url=None, form_class=None,
             disallowed_url='registration_disallowed',
             template_name='user/login_logout_register/registration_form.html',
             extra_context=None):
muntu
źródło

Odpowiedzi:

66

Po pierwsze, Twoja definicja adresu URL w ogóle nie akceptuje żadnych parametrów. Jeśli chcesz, aby parametry były przekazywane z adresu URL do widoku, musisz zdefiniować je w urlconf.

Po drugie, nie jest wcale jasne, czego oczekujesz od słownika clean_data. Nie zapominaj, że nie możesz przekierować do POST - jest to ograniczenie HTTP, a nie Django - więc twoje clean_data musi albo być parametrem adresu URL (okropne), albo, nieco lepiej, serią parametrów GET - więc adres URL miałby postać:

/link/mybackend/?field1=value1&field2=value2&field3=value3

i tak dalej. W tym przypadku field1, field2 i field3 nie są uwzględniane w definicji URLconf - są dostępne w widoku przez request.GET.

Więc twój urlconf wyglądałby tak:

url(r'^link/(?P<backend>\w+?)/$', my_function)

a widok wyglądałby tak:

def my_function(request, backend):
   data = request.GET

a odwrotnie (po zaimportowaniu urllib):

return "%s?%s" % (redirect('my_function', args=(backend,)),
                  urllib.urlencode(form.cleaned_data))

Edytowano po komentarzu

Cały sens używania przekierowania i odwrócenia, tak jak to robiłeś, polega na tym, że przechodzisz do adresu URL - zwraca kod HTTP, który powoduje, że przeglądarka przekierowuje do nowego adresu URL i wywołuje to.

Jeśli chcesz po prostu wywołać widok z kodu, po prostu zrób to bezpośrednio - nie musisz w ogóle używać odwrotności.

To powiedziawszy, jeśli wszystko, co chcesz zrobić, to zapisać dane, po prostu umieść je w sesji:

request.session['temp_data'] = form.cleaned_data
Daniel Roseman
źródło
a jeśli nie będę operował na clean_data w tym widoku, ale przekażę to do późniejszego wykorzystania? Mam wiele pól w
dyktandzie Cleaning_data,
Nie rozumiem tego komentarza. Proszę wyjaśnić bardziej szczegółowo, aktualizując swoje pytanie, jeśli to konieczne.
Daniel Roseman,
ten drugi widok zapisze te przesłane dane tylko do dalszego wykorzystania. Ale czy na pewno muszę podać adres URL? Z dokumentów wygląda na to, że bezpośrednio wywołuję widok. Miałem też nadzieję, że wyślę słownik z zapleczem i danymi w redirect () (tak jak to się dzieje w django-register), a następnie w adresie URL (jak ten dict w funkcji rejestru), ale z tego, co widzę, jest to niemożliwe?
muntu
tak tak tak to jest to !! Zmarnowałem na to tyle czasu zupełnie zapominając o sesjach: / cholera, dzięki !!
muntu
1
dobra uwaga na temat po prostu wywoływania funkcji, jeśli nie jest potrzebny adres URL.
maxbellec
60

urls.py:

#...    
url(r'element/update/(?P<pk>\d+)/$', 'element.views.element_update', name='element_update'),

views.py:

from django.shortcuts import redirect
from .models import Element


def element_info(request):
    # ...
    element = Element.object.get(pk=1)
    return redirect('element_update', pk=element.id)

def element_update(request, pk)
    # ...
sergi0
źródło