I'm trying to send an email to a user when a new model instance is saved and I want the email to include a link to the admin page for that model instance. Is there a way to get the correct URL? I figure Django must have that information stored somewhere.
5 Answers
Not trying to rip off @JosvicZammit, but using ContentType is the wrong approach here. It's just a wasted DB query. You can get the require info from the _meta attribute:
from django.urls import reverse
info = (model_instance._meta.app_label, model_instance._meta.model_name)
admin_url = reverse('admin:%s_%s_change' % info, args=(model_instance.pk,))
Comments
This Django snippet should do:
from django.urls import reverse
from django.contrib.contenttypes.models import ContentType
from django.db import models
class MyModel(models.Model):
def get_admin_url(self):
content_type = ContentType.objects.get_for_model(self.__class__)
return reverse("admin:%s_%s_change" % (content_type.app_label, content_type.model), args=(self.id,))
The self refers to the parent model class, i.e. self.id refers to the object's instance id. You can also set it as a property on the model by sticking the @property decorator on top of the method signature.
EDIT: The answer by Chris Pratt below saves a DB query over the ContentType table. My answer still "works", and is less dependent on the Django model instance._meta internals. FYI.
3 Comments
get_admin_url() above gets you the part that goes after the hostname. Use the Django sites framework to appropriately get the hostname of the current site. Then prefix it to the result of get_admin_url().This gives the same result as Josvic Zammit's snippet, but does not hit the database:
from django.urls import reverse
from django.db import models
class MyModel(models.Model):
def get_admin_url(self):
return reverse("admin:%s_%s_change" % (self._meta.app_label, self._meta.model_name), args=(self.id,))
4 Comments
module_name by model_name (module_name is undefined)admin:?Just use this one liner that is also python 3 ready:
from django.urls import reverse
reverse('admin:{0}_{1}_change'.format(self._meta.app_label, self._meta.model_name), args=(self.pk,))
More on this in the django admin site doc, reversing admin urls.
So, combining the answers by Chris, Josvic and Josh, here's a copy-paste method you can add into your model (tested on Django 1.8.3).
def get_admin_url(self):
"""the url to the Django admin interface for the model instance"""
from django.core.urlresolvers import reverse
info = (self._meta.app_label, self._meta.model_name)
return reverse('admin:%s_%s_change' % info, args=(self.pk,))