9

django.contrib.auth has an awesome feature: When you try to access a page that's decorated by login_required, you get redirected to the login page with a next argument, so after you login you get redirected back to the page you were originally trying to access. That's good for the user flow.

But, apparently django-registration does not provide a similar feature. I expected that if you register instead of login, you would also get a next thing, and after registering-n'-activating you'll get redirected to the page you were originally trying to visit. This is not the case, you're just redirected to some success page. This hurts the flow.

Does django-registration perhaps provide this option but I'm not using it or correctly? Or is there an easy way to do this?

Ram Rachum
  • 84,019
  • 84
  • 236
  • 374
  • Are you talking about when you do the signup, or when you activate via the email? – Timmy O'Mahony Oct 31 '11 at 08:49
  • After you signup, you activate by email, and then when you finish activation I'd expect you get redirected to the page you were originally trying to visit. – Ram Rachum Oct 31 '11 at 09:05

2 Answers2

12

If you look at the view responsible for the activation of an account via email (registration.views.activate) you'll see that it accepts a success_url parameter which is "The name of a URL pattern to redirect to on successful activation."

So you simply have to overwrite the url that calls that view and provide the page you wish to redirect to.

So in your own urls.py:

from registration.views import activate
urlpatterns = patterns('',
    url(r'^activate/(?P<activation_key>\w+)/$',
            activate,
            {'backend': 'registration.backends.default.DefaultBackend'},
            name='registration_activate',
            # You could use reverse() here instead of a URL to be DRY'er
            success_url = "http://..." 
            ),

Alternatively you could wrap up django-registrations activate view in your own view and accept a GET parameter to redirect to:

from registration.view import activate
def custom_activate(request, backend,
         template_name='registration/activate.html',
         success_url=None, extra_context=None, **kwargs):
    success_url = request.GET.get('next', None)
    return activate(request, template_name=template_name, success_url=success_url, extra_context=None, **kwargs)

Now, in your template registration/activation_email.html you can append the redirection location to the link:

{% url 'registration.view.activate' activation_key as a_url %}

Thanks! ....

{% autoescape off %}
<a href="http://{{ site.domain }}{{ a_url }}?next='http://somepage_or_url'">
    http://{{ site.domain }}{{ url_registration_activate }}/
</a>
{% endautoescape %}

Thanks!

EDIT

Ok, so the above deals with hard coded redirects. I'm guessing this is the flow you want:

  1. User tries to go to a page
  2. User gets redirected to a login/registration page
  3. User signs up on that page and gets sent an email
  4. User activates email and gets redirected to the original page they tried to view

This is more difficult as the page they were trying to view in step one needs to be passed all the way to step four and as we know, HTTP is stateless.

The first suggestion that comes to mind is to save the redirect in a session variable when you register and then retrieve it when you activate. To do this we can overwrite django-registrations default backend (which is just a class with methods that outline the functionality of the registration process and are called from the views), specifically the register and post_activation_redirect methods:

custom_backend.py

from registration.backends.default import DefaultBackend
class RedirectBackend(DefaultBackend):
    def register(self, request, **kwargs):
        request.session['redirect'] = request.GET.get("next",None)
        super(RedirectBackend, self).register(request, **kwargs)

    def post_activation_redirect(self, request, user):
        return(request.session['redirect'], (), {})

and to make sure django-registration actually uses this backend, we provide it to the views via our urls.py:

url(r'^activate/(?P<activation_key>\w+)/$',
    activate,
    {'backend': 'custombackend.RedirectBackend'},
    name='registration_activate'),
url(r'^register/$',
    register,
    {'backend': 'custombackend.RedirectBackend'},
    name='registration_register'),
Timmy O'Mahony
  • 53,000
  • 18
  • 155
  • 177
  • This is the second half. What about the first half, connecting the correct `next` URL with the person registering? – Ram Rachum Oct 31 '11 at 11:17
  • I don't understand what you mean – Timmy O'Mahony Oct 31 '11 at 11:31
  • The point is to redirect to the view that the user originally tried to visit, not to a constant URL. So how will you save and then later retrieve the URL that the user originally tried to visit? – Ram Rachum Nov 01 '11 at 00:03
  • I've updated my answer with an approach for redirection after activation with a dynamic URL (i.e. the url the user was trying to see originally) – Timmy O'Mahony Nov 01 '11 at 17:54
-4

You should use the same decorator @login_required, django-registration uses that too.

Pavel Shvedov
  • 1,284
  • 11
  • 8
  • And will that cause the user to be redirected after registration to the original page they were trying to visit? – Ram Rachum Oct 30 '11 at 06:53