
Creating a model mixin with URL-related methods
For every model that has its own page, it is good practice to define the get_absolute_url()
method. This method can be used in templates and also in the Django admin site to preview the saved object. However, get_absolute_url()
is ambiguous as it returns the URL path instead of the full URL. In this recipe, we will see how to create a model mixin that allows you to define either the URL path or the full URL by default, generate the other out of the box, and take care of the get_absolute_url()
method that is being set.
Getting ready
If you haven't done it yet, create the utils
package to save your mixins. Then, create the models.py
file in the utils
package (alternatively, if you create a reusable app, put the mixins in the base.py
file in your app).
How to do it…
Execute the following steps one by one:
- Add the following content to the
models.py
file of yourutils
package:# utils/models.py # -*- coding: UTF-8 -*- from __future__ import unicode_literals import urlparse from django.db import models from django.contrib.sites.models import Site from django.conf import settings class UrlMixin(models.Model): """ A replacement for get_absolute_url() Models extending this mixin should have either get_url or get_url_path implemented. """ class Meta: abstract = True def get_url(self): if hasattr(self.get_url_path, "dont_recurse"): raise NotImplementedError try: path = self.get_url_path() except NotImplementedError: raise website_url = getattr( settings, "DEFAULT_WEBSITE_URL", "http://127.0.0.1:8000" ) return website_url + path get_url.dont_recurse = True def get_url_path(self): if hasattr(self.get_url, "dont_recurse"): raise NotImplementedError try: url = self.get_url() except NotImplementedError: raise bits = urlparse.urlparse(url) return urlparse.urlunparse(("", "") + bits[2:]) get_url_path.dont_recurse = True def get_absolute_url(self): return self.get_url_path()
- To use the mixin in your app, import it from the
utils
package, inherit the mixin in your model class, and define theget_url_path()
method as follows:# demo_app/models.py # -*- coding: UTF-8 -*- from __future__ import unicode_literals from django.db import models from django.utils.translation import ugettext_lazy as _ from django.core.urlresolvers import reverse from django.utils.encoding import \ python_2_unicode_compatible from utils.models import UrlMixin @python_2_unicode_compatible class Idea(UrlMixin): title = models.CharField(_("Title"), max_length=200) # … get_url_path(self): return reverse("idea_details", kwargs={ "idea_id": str(self.pk), })
- If you check this code in the staging or production environment or run a local server with a different IP or port than the defaults, set
DEFAULT_WEBSITE_URL
in your local settings (without the trailing slash), as follows:# settings.py # … DEFAULT_WEBSITE_URL = "http://www.example.com"
How it works…
The UrlMixin
class is an abstract model that has three methods: get_url()
, get_url_path()
, and get_absolute_url()
. The get_url()
or get_url_path()
methods are expected to be overwritten in the extended model class, for example, Idea
. You can define get_url()
, which is the full URL of the object, and then get_url_path()
will strip it to the path. You can also define get_url_path()
, which is the absolute path of the object, and then get_url()
will prepend the website URL to the beginning of the path. The get_absolute_url()
method will mimic the get_url_path()
method.
Tip
The rule of thumb is to always overwrite the get_url_path()
method.
In the templates, use <a href="{{ idea.get_url_path }}">{{ idea.title }}</a>
when you need a link of an object in the same website. Use <a href="{{ idea.get_url }}">{{ idea.title }}</a>
for the links in e-mails, RSS feeds, or APIs.
The default get_absolute_url()
method will be used in the Django model administration for the View on site functionality and might also be used by some third-party Django apps.
See also
- The Using model mixins recipe
- The Creating a model mixin to handle creation and modification dates recipe
- The Creating a model mixin to take care of meta tags recipe
- The Creating a model mixin to handle generic relations recipe