Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases now! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Django 3 Web Development Cookbook

You're reading from   Django 3 Web Development Cookbook Actionable solutions to common problems in Python web development

Arrow left icon
Product type Paperback
Published in Mar 2020
Publisher Packt
ISBN-13 9781838987428
Length 608 pages
Edition 4th Edition
Languages
Tools
Arrow right icon
Authors (2):
Arrow left icon
Jake Kronika Jake Kronika
Author Profile Icon Jake Kronika
Jake Kronika
Aidas Bendoraitis Aidas Bendoraitis
Author Profile Icon Aidas Bendoraitis
Aidas Bendoraitis
Arrow right icon
View More author details
Toc

Table of Contents (15) Chapters Close

Preface 1. Getting Started with Django 3.0 2. Models and Database Structure FREE CHAPTER 3. Forms and Views 4. Templates and JavaScript 5. Custom Template Filters and Tags 6. Model Administration 7. Security and Performance 8. Hierarchical Structures 9. Importing and Exporting Data 10. Bells and Whistles 11. Testing 12. Deployment 13. Maintenance 14. Other Books You May Enjoy

Creating a model mixin with URL-related methods

For every model that has its own distinct detail 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 look at how to create a model mixin that provides simplified support for model-specific URLs. This mixin will enable you to do the following:

  • Allow you to define either the URL path or the full URL in your model
  • Generate the other URL automatically, based on the one that you defined
  • Define the get_absolute_url() method behind the scenes

Getting ready

If you haven't yet done so, create the myproject.apps.core app where you will store your model mixins. Then, create a models.py file in the core package. Alternatively, if you create a reusable app, put the mixins in a base.py file in that app.

How to do it...

Execute the following steps, one by one:

  1. Add the following content to the models.py file of your core app:
# myproject/apps/core/models.py
from urllib.parse import urlparse, urlunparse
from django.conf import settings
from django.db import models

class UrlBase(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
return settings.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(url)
return urlunparse(("", "") + bits[2:])
get_url_path.dont_recurse = True

def get_absolute_url(self):
return self.get_url()
  1. Add the WEBSITE_URL setting without a trailing slash to the dev, test, staging, and production settings. For example, for the development environment this will be as follows:
# myproject/settings/dev.py
from
._base import *

DEBUG = True
WEBSITE_URL = "http://127.0.0.1:8000" # without trailing slash
  1. To use the mixin in your app, import the mixin from the core app, inherit the mixin in your model class, and define the get_url_path() method, as follows:
# myproject/apps/ideas/models.py
from django.db import models
from django.urls import reverse
from django.utils.translation import gettext_lazy as _

from myproject.apps.core.models import UrlBase

class Idea(UrlBase):
# fields, attributes, properties and methods…

def get_url_path(self):
return reverse("idea_details", kwargs={
"idea_id": str(self.pk),
})

How it works...

The UrlBase class is an abstract model that has three methods, as follows:

  • get_url() retrieves the full URL of the object.
  • get_url_path() retrieves the absolute path of the object.
  • get_absolute_url() mimics the get_url_path() method.

The get_url() and get_url_path() methods are expected to be overwritten in the extended model class, for example, Idea. You can define get_url(), and get_url_path() will strip it to the path. Alternatively, you can define get_url_path(), and get_url() will prepend the website URL to the beginning of the path.

The rule of thumb is to always overwrite the get_url_path() method.

In the templates, use get_url_path() when you need a link to an object on the same website, as follows:

<a href="{{ idea.get_url_path }}">{{ idea.title }}</a>

Use get_url() for links in external communication, such as in emails, RSS feeds, or APIs; an example is as follows:

<a href="{{ 
idea.get_url }}">{{ idea.title }}</a>

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.

There's more...

In general, don't use incremental primary keys in the URLs, because it is not safe to expose them to the end user: the total amount of items would be visible, and it would be too easy to navigate through different items by just changing the URL path.

You can use the primary keys in the URLs for the detail pages only if they are Universal Unique Identifiers (UUIDs) or generated random strings. Otherwise, create and use a slug field, as follows:

class Idea(UrlBase):
slug = models.SlugField(_("Slug for URLs"), max_length=50)

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
  • The Configuring settings for development, testing, staging, and production environments recipe, in Chapter 1, Getting Started with Django 3.0
You have been reading a chapter from
Django 3 Web Development Cookbook - Fourth Edition
Published in: Mar 2020
Publisher: Packt
ISBN-13: 9781838987428
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime