Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding link to django admin page

I have a client that has an app built with django. On every page of their app is a link to their admin site. They tell me the admin site is generated entirely by django, and they've never customized it before. On the very first line of the admin page it says:

Django administration          Welcome, admin. Change password / Log out

They want me to add a link to that line, to the left of "Django administration" that will take them back to the page they were on when they clicked on the link to get them to the admin site.

So I have 2 issues here:

  1. How do I override that line to add the link? It appears that page is generated by contrib/admin/templates/admin/base.html, and I tried to override it by following the directions at https://docs.djangoproject.com/en/1.2/ref/contrib/admin/#overriding-a..., but whatever I do seems to have no effect.

  2. How can I get the link of the page of the app they came from? It's not simply just going back one page, as they could have navigated all over the place of the admin site before clicking the "Back to app" link.

like image 619
Larry Martell Avatar asked Mar 26 '12 14:03

Larry Martell


2 Answers

There are many ways to store the last visited non-admin url in request.session. For example, a middleware:

import re

class LastSiteUrl(object):
    def is_admin_url(self, url):
        return re.search('^(http:\/\/.*){0,1}\/admin\/', url) is not None

    def process_request(self, request):
        if self.is_admin_url(request.path) and \
            not self.is_admin_url(request.META.get('HTTP_REFERER','')):
            request.session['last_site_url'] = request.META.get('HTTP_REFERER','')

Then override the template:

  1. Store the last non admin url in request.session, e.g. put the above class in yourproject/middleware.py, add to settings.MIDDLEWARE_CLASSES: middleware.LastSiteUrl

  2. Prepare the admin base site template for overriding, copy django/contrib/admin/templates/admin/base_site.html to yourproject/templates/admin/base_site.html

  3. Link to request.session.last_site_url, e.g. in yourproject/templates/admin/base_site.html, find {% block branding %}, before the H1 tag of this block, add an HTML link to {{ request.session.last_site_url }}.

It should look like that:

{% block branding %}
    {% if request.session.last_site_url %}
        <a href="{{ request.session.last_site_url }}">back to site</a>
    {% endif %}
    <h1 id="site-name">{% trans 'Django administration' %}</h1>
{% endblock %}
like image 188
jpic Avatar answered Sep 20 '22 21:09

jpic


The easy way:

If a model has a get_absolute_url function, the admin 'change' pages contain a 'view on site' button on the top right of the page. So make sure your Model contains get_absolute_url:

    def get_absolute_url(self):
        return '/myapp/%s' %self.slug #this should reflect your url-structure.

The 'view on site' button is not on the 'add' page because the object needs to be created before you can visit it. Tell your client when he/she is creating a new object to NOT hit 'save' but 'save and continue editing' and than click on 'view on site'.

Now it's also easy to jump to the website representation of the current model entry by overriding the base_site.html. Here we check if the current model contains absolute_url. If you are not on a change_page, there won't be a absolute_url. In this case the link takes you to the homepage.

templates/admin/base_site.html

{% extends "admin/base.html" %}
{% load i18n %}

{% block title %}{{ title }} | {% trans 'Django site admin' %}{% endblock %}

{% block branding %}
<h1 id="site-name">{% if has_absolute_url %}<a href="../../../r/{{ content_type_id }}/{{ object_id }}/" class="viewsitelink">{% else %}<a href="http://{{ site.domain }}">{% endif %}{{ site.domain }}</a>    

 Sitebeheer{#{% trans 'Django administration' %}#}</h1>
{% endblock %}

{% block nav-global %}{% endblock %}

Done!

The following solution does also answer your question but in a different way. This will add a 'save and view on site' button next to 'save and continue' and 'save' buttons on the admin 'add' and 'change' pages:

  1. Make sure your model contains a get_absolute_url function.
  2. Override the admin response to redirect to this absolute_url.
  3. Override change_form.html to add a 'save and view on site' button.

Edit myproject/myapp/models.py

class MyModel(models.Model):
    title = models.CharField("titel", max_length=200)
    slug = models.SlugField(unique=True)

    def __unicode__(self):
        return self.title

    def get_absolute_url(self):
        return '/myapp/%s' %self.slug

Edit myproject/myapp/admin.py

from models import MyModel

class MyModelAdmin(admin.ModelAdmin):
    ...

    def response_change(self, request, obj):
        """
        Determines the HttpResponse for the change_view stage.
        """
        if request.POST.has_key("_viewsite"):
            msg = (_('The %(name)s "%(obj)s" was changed successfully.') %
                   {'name': force_unicode(obj._meta.verbose_name),
                    'obj': force_unicode(obj)})
            return HttpResponseRedirect(obj.get_absolute_url())
        return super(MyModel, self).response_change(request, obj)

admin.site.register(MyModel, MyModelAdmin)

Create a new file myproject/templates/admin/myapp/change_form.html:

{% extends "admin/change_form.html" %}
{% load i18n %}
{% block content %}
{{ block.super }}
<script type="text/javascript">//<![CDATA[
    (function($){
        $('<input type="submit" value="Save and view on site" name="_viewsite" />')
        .prependTo('div.submit-row');
    })(django.jQuery);
//]]></script>
{% endblock %}

The template will override the change_form for each model in the myapp. This could be undesirable in your situation because not all models have a representation in the website (don't have and don't need get_absolute_url). I think you can also put the template at myproject/templates/admin/myapp/MyModel/change_form.html to only override the template for MyModel and leave other models in myapp with de default template. I never used a change_form template for a single model. Will you let me know if it worked?

A big thank you for: http://djangosnippets.org/snippets/2005/

Did this answer your question? I hope it helps.

like image 43
allcaps Avatar answered Sep 18 '22 21:09

allcaps