Conor Svensson
Conor Svensson

Reputation: 1251

Passing a parameter to a class based view from a redirect

I have a class based view (RegistrationView) which I'd like to pass a parameter value to upon redirect, as per the following.

# views.py
def hook(request):
    return HttpResponseRedirect(reverse('registration_register',
                                    kwargs={'initial': {'email': '[email protected]'}}))

Where my accompanying URL pattern for this is defined as:

# urls.py
urlpatterns = [
    url(r'^account/register/$',
        RegistrationView.as_view(form_class=RegistrationForm), 
        name='registration_register'),
]

And initial is a valid parameter value in RegistrationView.

However, when I run this, I hit the following error, as I have not defined the argument in my urls (and I don't want to have to define the parameter in the url path if possible).

Reverse for 'registration_register' with arguments '()' and keyword arguments '{'initial': {'email': '[email protected]'}}' not found. 1 pattern(s) tried: ['account/register/$']

I came across the following query which discusses passing keyword arguments to class based views, however, I have not been able to get it to work with the above code.

Conceptually what I am trying to achieve is the equivalent of the below, except using a HttpRedirect instead of generating a straight response.

def hook(request):
    return RegistrationView.as_view(
         form_class=RegistrationForm, initial={'email': '[email protected]'})(request)

Is anyone able to advise how I can redirect to my view with this initial parameter value?

Upvotes: 0

Views: 2582

Answers (2)

Daniel Hepper
Daniel Hepper

Reputation: 29977

You are mixing up a few things.

The parameters you pass to reverse with args and kwargs are used to build a URL. For a view to accept these arguments, the corresponding URL pattern has to have a placeholder for it.

Have a look at this example:

# urls.py
...
url(r'^/polls/(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
...

# views.py
def detail(request, question_id):
    return HttpResponse("You're looking at question %s." % question_id)

>>> reverse('detail', kwargs={'question_id': 123})
'/polls/123/'

If you want to pass any extra information, you can use query paramters, e.g.

/polls/123/?foo=bar

reverse is only responsible for the path portion of the URL, i.e until the ?, you have to build the whole this manually.

django.utils.http import urlencode
path = reverse('detail', kwargs={'question_id': 123})
params = urlencode({'foo': 'bar'})
url = "%s?%s" % (path, params)

You can access query parameters in your view with request.GET, in this example request.GET.get('foo').

Now, regarding your class based view. Simply speaking, as_view() is the wrong place to look to pass arguments that should be different for each request. Under the hood, the expression RegistrationView.as_view(form_class=RegistrationForm) creates a factory function, which instantiates a new RegistrationView instance for every request. as_view() "stores" its arguments and passes them to RegistrationView.__init__().

TL;DR:

Pass the email as query parameter, like the parameter next in the login URL.

/account/register/[email protected]

If your RegistrationView is a standard FormView, you can overwrite get_initial to fetch the parameter.

def get_initial(self):
    initial = super(RegistrationView, self).get_initial()
    email = self.request.GET.get('email')
    if email is not None:
        initial['email'] = email
    return initial

Upvotes: 4

Daniel Roseman
Daniel Roseman

Reputation: 599450

Well, as you say, you haven't defined that parameter in your URL, so I don't know what you think the reverse function is going to do with it. Despite what you say about it being a "valid parameter" for RegistrationView, it's clear that that view doesn't expect that parameter either.

If you want to pass this data via reverse, you need to write a view that does expect parameters, and give it a URL that accepts those parameters.

An alternative might be to pass this data using the session.

Upvotes: 1

Related Questions