227

Before Django 1.0 there was an easy way to get the admin url of an object, and I had written a small filter that I'd use like this: <a href="{{ object|admin_url }}" .... > ... </a>

Basically I was using the url reverse function with the view name being 'django.contrib.admin.views.main.change_stage'

reverse( 'django.contrib.admin.views.main.change_stage', args=[app_label, model_name, object_id] )

to get the url.

As you might have guessed, I'm trying to update to the latest version of Django, and this is one of the obstacles I came across, that method for getting the admin url doesn't work anymore.

How can I do this in django 1.0? (or 1.1 for that matter, as I'm trying to update to the latest version in the svn).

Kara
  • 6,115
  • 16
  • 50
  • 57
hasen
  • 161,647
  • 65
  • 194
  • 231

10 Answers10

535

You can use the URL resolver directly in a template, there's no need to write your own filter. E.g.

{% url 'admin:index' %}

{% url 'admin:polls_choice_add' %}

{% url 'admin:polls_choice_change' choice.id %}

{% url 'admin:polls_choice_changelist' %}

Ref: Documentation

blueyed
  • 27,102
  • 4
  • 75
  • 71
markmuetz
  • 9,334
  • 2
  • 32
  • 33
  • 1
    markmuetz - Is this in the official Django docs anywhere? (how to use admin reverse URLs in templates)? If not, it should be. – shacker Jul 29 '10 at 07:04
  • 9
    shacker - It's all in the docs... just not in one place. The "url" template tag is documented [here](http://docs.djangoproject.com/en/1.2/ref/templates/builtins/#url). In the section "New in Django 1.1:" the docs say that namespaced URLs are fine, and points you to [the section on URL namespaces](http://docs.djangoproject.com/en/1.2/topics/http/urls/#topics-http-reversing-url-namespaces). Sticking it all together lets you reference the admin application easily in templates. N.B I remember the docs being different when I wrote the reply. – markmuetz Aug 03 '10 at 10:29
  • 3
    Do you know how to get a link to the "list" of choices? Example: if "{% url admin:polls_choice_add %}" gives "/admin/polls/choice/add" what would be the equivalent that would give me "/admin/polls/choice"? – DarwinSurvivor Feb 11 '11 at 00:07
  • 3
    {% url admin:polls_choice_changelist %} returns the '/admin/polls/choice' url – luc Aug 31 '11 at 09:24
  • 47
    Reversing an admin url is currently fully documented here [https://docs.djangoproject.com/en/dev/ref/contrib/admin/#reversing-admin-urls](https://docs.djangoproject.com/en/dev/ref/contrib/admin/#reversing-admin-urls) – Josh Russo Sep 11 '11 at 23:45
  • 1
    Note that in Django 1.5, you'll need to have the view name in quotes. E.g., `{% url "admin:index" %}`. – Josh Aug 26 '13 at 17:39
  • 1
    I spent the better part of a day looking for this answer. It seems like there should be another question specifically for "How to get a Django admin app object change URL for an object in a template" – Alex Willison Aug 02 '17 at 17:57
  • Is there a way to use the `url` tag with the flexibility of the OP's filter with parameters for the app name and model name? – Code-Apprentice Jun 21 '19 at 22:21
  • My multi-word model names were causing a problem. Don't use an underscore between words, e.g. `MyChoice` would be `{% url 'admin:polls_mychoice_changelist' %}` – Dave May 05 '20 at 21:06
122
from django.core.urlresolvers import reverse
def url_to_edit_object(obj):
  url = reverse('admin:%s_%s_change' % (obj._meta.app_label,  obj._meta.model_name),  args=[obj.id] )
  return u'<a href="%s">Edit %s</a>' % (url,  obj.__unicode__())

This is similar to hansen_j's solution except that it uses url namespaces, admin: being the admin's default application namespace.

omushpapa
  • 1,663
  • 20
  • 25
Mike Ramirez
  • 10,750
  • 3
  • 26
  • 20
  • 4
    Thanks, it helps. One thing i would change: use `args=[object.pk]` instead of `args=[object.id]`. It covers more common case, when primary key field has another name than `id`. – stalk May 28 '13 at 10:46
  • 6
    Good answer. FYI anyone using a more recent django will need to change object._meta.module_name to object._meta.model_name – Jagu Jun 22 '15 at 00:12
  • Big thank you from a django newbie. `object._meta.app_label` let me ultimately get the name for django's own authentication app. It's `auth`, for example `reverse(admin:auth_user_change, args=[object.id])` to jump to the change user page – Gret Sep 29 '17 at 06:33
  • 2
    Be sure to change object to obj. This guy is over writing a reserved built in symbol. – Kevin Parker Aug 29 '19 at 18:32
65

I had a similar issue where I would try to call reverse('admin_index') and was constantly getting django.core.urlresolvers.NoReverseMatch errors.

Turns out I had the old format admin urls in my urls.py file.

I had this in my urlpatterns:

(r'^admin/(.*)', admin.site.root),

which gets the admin screens working but is the deprecated way of doing it. I needed to change it to this:

(r'^admin/', include(admin.site.urls) ),

Once I did that, all the goodness that was promised in the Reversing Admin URLs docs started working.

djvg
  • 11,722
  • 5
  • 72
  • 103
bskinnersf
  • 3,090
  • 1
  • 20
  • 10
  • Awesome, this fixed another issue I was having with the get_urls() method of ModelAdmin not being called. Thanks! – Arnaud Oct 01 '09 at 10:12
  • 10
    best url for this problem: http://docs.djangoproject.com/en/dev/ref/contrib/admin/#reversing-admin-urls – Dingo Mar 02 '11 at 09:11
  • 4
    This "answer" is not correct it just shows how to properly add the admin app to your app, which solved a different problem that the author had. The real answer to the actual question is below - from markmuetz – Declan Shanaghy Aug 19 '11 at 18:18
  • Also, you need to have registered admin interface for the model, otherwise the URL won't exist. – Flimm Feb 03 '16 at 13:07
24

Essentially the same as Mike Ramirez's answer, but simpler and closer in stylistics to django standard get_absolute_url method:

from django.urls import reverse

def get_admin_url(self):
    return reverse('admin:%s_%s_change' % (self._meta.app_label, self._meta.model_name),
                   args=[self.id])
Antony Hatchkins
  • 31,947
  • 10
  • 111
  • 111
20

Using template tag admin_urlname:

There's another way for the later versions (>=1.10), recommend by the Django documentation, using the template tag admin_urlname:

{% load admin_urls %}
<a href="{% url opts|admin_urlname:'add' %}">Add user</a>
<a href="{% url opts|admin_urlname:'delete' user.pk %}">Delete this user</a>

Where opts is something like mymodelinstance._meta or MyModelClass._meta

One gotcha is you can't access underscore attributes directly in Django templates (like {{ myinstance._meta }}) so you have to pass the opts object in from the view as template context.

Flimm
  • 136,138
  • 45
  • 251
  • 267
Anentropic
  • 32,188
  • 12
  • 99
  • 147
  • 3
    The docs url has changed! See: https://docs.djangoproject.com/en/1.9/ref/contrib/admin/#reversing-admin-urls – Wim Feijen Mar 27 '16 at 14:04
  • 1
    Since Wim's URL is dead, here's a working one: https://docs.djangoproject.com/en/dev/ref/contrib/admin/#reversing-admin-urls – sodimel Jan 16 '23 at 19:33
17

For pre 1.1 django it is simple (for default admin site instance):

reverse('admin_%s_%s_change' % (app_label, model_name), args=(object_id,))
Alex Koshelev
  • 16,879
  • 2
  • 34
  • 28
3

If you are using 1.0, try making a custom templatetag that looks like this:

def adminpageurl(object, link=None):
    if link is None:
        link = object
    return "<a href=\"/admin/%s/%s/%d\">%s</a>" % (
        instance._meta.app_label,
        instance._meta.module_name,
        instance.id,
        link,
    )

then just use {% adminpageurl my_object %} in your template (don't forget to load the templatetag first)

DarwinSurvivor
  • 365
  • 3
  • 12
3

I solved this by changing the expression to:

reverse( 'django-admin', args=["%s/%s/%s/" % (app_label, model_name, object_id)] )

This requires/assumes that the root url conf has a name for the "admin" url handler, mainly that name is "django-admin",

i.e. in the root url conf:

url(r'^admin/(.*)', admin.site.root, name='django-admin'),

It seems to be working, but I'm not sure of its cleanness.

hasen
  • 161,647
  • 65
  • 194
  • 231
  • 2
    This works for 1.0, but will not work for 1.1, which has a better solution: see Alex Koshelev's answer. – Carl Meyer Mar 29 '09 at 15:08
  • Actually I tried it and it didn't work, and he said it's for 1.0, no? – hasen Mar 29 '09 at 15:25
  • Syntax has changed in 1.1 with the introduction of url namespacing: http://docs.djangoproject.com/en/dev/topics/http/urls/#topics-http-reversing-url-namespaces – sleepyjames Aug 04 '09 at 16:14
0

For going to the admin page or admin login page we can use the below link. It works for me -

{% url 'admin:index' %}

This url takes me directly to the admin page.

Mehedi Abdullah
  • 772
  • 10
  • 13
-1

Here's another option, using models:

Create a base model (or just add the admin_link method to a particular model)

class CommonModel(models.Model):
    def admin_link(self):
        if self.pk:
            return mark_safe(u'<a target="_blank" href="../../../%s/%s/%s/">%s</a>' % (self._meta.app_label,
                    self._meta.object_name.lower(), self.pk, self))
        else:
            return mark_safe(u'')
    class Meta:
        abstract = True

Inherit from that base model

   class User(CommonModel):
        username = models.CharField(max_length=765)
        password = models.CharField(max_length=192)

Use it in a template

{{ user.admin_link }}

Or view

user.admin_link()
Ian Cohen
  • 576
  • 2
  • 7
  • 15
  • 2
    I don't think this is a good solution. Building a URL with string formatting is a bad habit. Please use reverse(). – guettli Mar 12 '14 at 10:42