How to implement a "back" link on Django Templates?
Asked Answered
O

10

43

I'm tooling around with Django and I'm wondering if there is a simple way to create a "back" link to the previous page using the template system.

I figure that in the worst case I can get this information from the request object in the view function, and pass it along to the template rendering method, but I'm hoping I can avoid all this boilerplate code somehow.

I've checked the Django template docs and I haven't seen anything that mentions this explicitly.

Outgrowth answered 8/2, 2009 at 2:2 Comment(1)
When you go back, the page is re-rendered, this means any processing (database queries, resource downloading etc) happens all over again. To prevent that, use @cache_page decorator.Limburger
F
12

Well you can enable:

'django.core.context_processors.request',

in your settings.TEMPLATE_CONTEXT_PROCESSORS block and hook out the referrer but that's a bit nauseating and could break all over the place.

Most places where you'd want this (eg the edit post page on SO) you have a real object to hook on to (in that example, the post) so you can easily work out what the proper previous page should be.

Fondly answered 8/2, 2009 at 2:8 Comment(3)
This is good info, and I stumbled onto "Model.get_absolute_url" in the docs after reading this. This actually solves the problem in my case, but I'm still curious the best course of action if you didn't have an object to point to.Outgrowth
Really depends on the circumstance. If there is some way of working out which page "should" be the previous page, I'd go that way.. But some times that's not possible and referrer checking might be your only option (other than letting users use their back button).Fondly
I once went down the path of trying to do this via session variables, but that was a mistake; brittle and broke all the time. Your choices are the ones Oli mentioned, or else using JavaScript to click the Back button for them.Brittaney
K
56

Actually it's go(-1).

<input type=button value="Previous Page" onClick="javascript:history.go(-1);">
Kinaesthesia answered 20/3, 2009 at 14:33 Comment(3)
Responses to other answers belong in the comments not in a new answer.Outgrowth
didn;t work in safari for me. For all browsers use this: onClick="window.history.back();return false;"Rafiq
Neither of these methods will work if Javascript is disabled.Tetrarch
B
51

This solution worked out for me:

<a href="{{request.META.HTTP_REFERER}}">Go back</a>

But that's previously adding 'django.core.context_processors.request', to TEMPLATE_CONTEXT_PROCESSORS in your project's settings.

Breakable answered 11/11, 2014 at 14:49 Comment(4)
this works , but after django 1.10 is :'django.template.context_processors.request',Bono
if you have 'django.template.context_processors.request', in your templates section of your settings.py file then all you have to do is add the HTML part to your template and it will work.Kalmuck
Only works if you tapped a button with a link, otherwise if you put in the source manually and tap the "Go back" button, nothing will happen.Middelburg
This causes a problem when there are two such buttons on two consecutive pages, as they will send the user back and forth between those, since the HTTP_REFERER will always be the other page respectively.Evitaevitable
E
16
<a href="{{request.META.HTTP_REFERER|escape}}">Back</a>

Here |escape is used to get out of the " "string.

Evacuate answered 4/6, 2018 at 21:47 Comment(3)
simple, elegant, effective.Mast
Thanks it worked for. Simple and straight forward.Authoritative
Similar answer posted four years prior here by @Pegasus. :-)Allomorph
F
12

Well you can enable:

'django.core.context_processors.request',

in your settings.TEMPLATE_CONTEXT_PROCESSORS block and hook out the referrer but that's a bit nauseating and could break all over the place.

Most places where you'd want this (eg the edit post page on SO) you have a real object to hook on to (in that example, the post) so you can easily work out what the proper previous page should be.

Fondly answered 8/2, 2009 at 2:8 Comment(3)
This is good info, and I stumbled onto "Model.get_absolute_url" in the docs after reading this. This actually solves the problem in my case, but I'm still curious the best course of action if you didn't have an object to point to.Outgrowth
Really depends on the circumstance. If there is some way of working out which page "should" be the previous page, I'd go that way.. But some times that's not possible and referrer checking might be your only option (other than letting users use their back button).Fondly
I once went down the path of trying to do this via session variables, but that was a mistake; brittle and broke all the time. Your choices are the ones Oli mentioned, or else using JavaScript to click the Back button for them.Brittaney
P
3

You can always use the client side option which is very simple:

<a href="javascript:history.go(1)">Back</a>
Prismatoid answered 18/3, 2009 at 10:50 Comment(3)
I really hate such links. Firstly, they doesn't work when you come to a page from a saved link/another site. Secondly, I enable Javascript only for trusted sites (using NoScript firefox extension). There're other reasons, but comment space is limited.Aklog
It's not the best coding ever I agree. But the high advantage is ultra simple and it works. It would also work if you come from a different site as it using the browsers BACK functionality regardless where you came from.Prismatoid
you meant go(-1)?Immerge
I
3

For RESTful links where "Back" usually means going one level higher:

<a href="../"><input type="button" value="Back" class="btn btn-primary" /></a>
Ironist answered 12/12, 2019 at 12:48 Comment(0)
C
2

All Javascript solutions mentioned here as well as the request.META.HTTP_REFERER solution sometimes work, but both break in the same scenario (and maybe others, too).

I usually have a Cancel button under a form that creates or changes an object. If the user submits the form once and server side validation fails, the user is presented the form again, containing the wrong data. Guess what, request.META.HTTP_REFERER now points to the URL that displays the form. You can press Cancel a thousand times and will never get back to where the initial edit/create link was.

The only solid solution I can think of is a bit involved, but works for me. If someone knows of a simpler solution, I'd be happy to hear from it. :-) The 'trick' is to pass the initial HTTP_REFERER into the form and use it from there. So when the form gets POSTed to, it passes the correct, initial referer along.

Here is how I do it:

I created a mixin class for forms that does most of the work:

from django import forms
from django.utils.http import url_has_allowed_host_and_scheme

class FormCancelLinkMixin(forms.Form):
    """ Mixin class that provides a proper Cancel button link. """
    cancel_link = forms.fields.CharField(widget=forms.HiddenInput())

    def __init__(self, *args, **kwargs):
        """
        Override to pop 'request' from kwargs.
        """
        self.request = kwargs.pop("request")
        initial = kwargs.pop("initial", {})
        # set initial value of 'cancel_link' to the referer
        initial["cancel_link"] = self.request.META.get("HTTP_REFERER", "")
        kwargs["initial"] = initial
        super().__init__(*args, **kwargs)

    def get_cancel_link(self):
        """
        Return correct URL for cancelling the form.

        If the form has been submitted, the HTTP_REFERER in request.meta points to
        the view that handles the form, not the view the user initially came from.
        In this case, we use the value of the 'cancel_link' field.

        Returns:
            A safe URL to go back to, should the user cancel the form.

        """
        if self.is_bound:
            url = self.cleaned_data["cancel_link"]
            # prevent open redirects
            if url_has_allowed_host_and_scheme(url, self.request.get_host()):
                return url

        # fallback to current referer, then root URL
        return self.request.META.get("HTTP_REFERER", "/")

The form that is used to edit/create the object (usually a ModelForm subclass) might look like this:

class SomeModelForm(FormCancelLinkMixin, forms.ModelForm):
    """ Form for creating some model instance. """

    class Meta:
        model = ModelClass
    # ...

The view must pass the current request to the form. For class based views, you can override get_form_kwargs():

class SomeModelCreateView(CreateView):
    model = SomeModelClass
    form_class = SomeModelForm

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs["request"] = self.request
        return kwargs

In the template that displays the form:

<form method="post">
  {% csrf token %}
  {{ form }}
  <input type="submit" value="Save">
  <a href="{{ form.get_cancel_link }}">Cancel</a>
</form>
Cloakroom answered 14/1, 2021 at 11:19 Comment(0)
A
0

For a 'back' button in change forms for Django admin what I end up doing is a custom template filter to parse and decode the 'preserved_filters' variable in the template. I placed the following on a customized templates/admin/submit_line.html file:

<a href="../{% if original}../{% endif %}?{{ preserved_filters | decode_filter }}">
    {% trans "Back" %}
</a>

And then created a custom template filter:

from urllib.parse import unquote
from django import template

def decode_filter(variable):
    if variable.startswith('_changelist_filters='):
        return unquote(variable[20:])
    return variable

register = template.Library()
register.filter('decode_filter', decode_filter)
Aerial answered 11/8, 2016 at 11:27 Comment(0)
C
0

Using client side solution would be the proper solution.

<a href="javascript:history.go(-1)" class="btn btn-default">Cancel</a>
Carcass answered 28/9, 2016 at 11:26 Comment(0)
W
0

In web development, there are various methods to implement a back button. I'd like to share two common approaches.

  1. Using JavaScript with onclick:
<button onclick="history.back()">Back</button>

This method utilizes JavaScript's history.back() function to navigate to the previous page in the browser history. It's a straightforward and effective solution.

  1. Using HTTP_REFERER like other comments above:
<a href="{{request.META.HTTP_REFERER}}">Back</a>

All this ways make store an history of pages, so if you open the page without historic and try back it don't will work, just reload the page. This work as intend.

Whitecap answered 24/12, 2023 at 11:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.