Sign In Start Free Trial
Account

Add to playlist

Create a Playlist

Modal Close icon
You need to login to use this feature.
  • Book Overview & Buying Django 3 Web Development Cookbook
  • Table Of Contents Toc
  • Feedback & Rating feedback
Django 3 Web Development Cookbook

Django 3 Web Development Cookbook

By : Aidas Bendoraitis, Jake Kronika
3.6 (9)
close
close
Django 3 Web Development Cookbook

Django 3 Web Development Cookbook

3.6 (9)
By: Aidas Bendoraitis, Jake Kronika

Overview of this book

Django is a web framework for perfectionists with deadlines, designed to help you build manageable medium and large web projects in a short time span. This fourth edition of the Django Web Development Cookbook is updated with Django 3's latest features to guide you effectively through the development process. This Django book starts by helping you create a virtual environment and project structure for building Python web apps. You'll learn how to build models, views, forms, and templates for your web apps and then integrate JavaScript in your Django apps to add more features. As you advance, you'll create responsive multilingual websites, ready to be shared on social networks. The book will take you through uploading and processing images, rendering data in HTML5, PDF, and Excel, using and creating APIs, and navigating different data types in Django. You'll become well-versed in security best practices and caching techniques to enhance your website's security and speed. This edition not only helps you work with the PostgreSQL database but also the MySQL database. You'll also discover advanced recipes for using Django with Docker and Ansible in development, staging, and production environments. By the end of this book, you will have become proficient in using Django's powerful features and will be equipped to create robust websites.
Table of Contents (15 chapters)
close
close

Creating a model mixin to handle generic relations

Aside from normal database relationships, such as a foreign-key relationship or a many-to-many relationship, Django has a mechanism to relate a model to an instance of any other model. This concept is called generic relations. For each generic relation, we save the content type of the related model as well as the ID of the instance of that model.

In this recipe, we will look at how to abstract the creation of generic relations in the model mixins.

Getting ready

For this recipe to work, you will need to have the contenttypes app installed. It should be in the INSTALLED_APPS list in the settings, by default, as shown in the following code:

# myproject/settings/_base.py

INSTALLED_APPS = [
# contributed
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
# third-party
# ...
# local
"myproject.apps.core",
"myproject.apps.categories",
"myproject.apps.ideas",
]

Again, make sure that you have already created the myproject.apps.core app for your model mixins.

How to do it...

To create and use a mixin for generic relations follow these steps:

  1. Open the models.py file in the core package in a text editor, and insert the following content there:
# myproject/apps/core/models.py
from django.db import models
from django.utils.translation import gettext_lazy as _
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey
from django.core.exceptions import FieldError


def object_relation_base_factory(
prefix=None,
prefix_verbose=None,
add_related_name=False,
limit_content_type_choices_to=None,
is_required=False):
"""
Returns a mixin class for generic foreign keys using
"Content type - object ID" with dynamic field names.
This function is just a class generator.

Parameters:
prefix: a prefix, which is added in front of
the fields
prefix_verbose: a verbose name of the prefix, used to
generate a title for the field column
of the content object in the Admin
add_related_name: a boolean value indicating, that a
related name for the generated content
type foreign key should be added. This
value should be true, if you use more
than one ObjectRelationBase in your
model.

The model fields are created using this naming scheme:
<<prefix>>_content_type
<<prefix>>_object_id
<<prefix>>_content_object
"""
p = ""
if prefix:
p = f"{prefix}_"

prefix_verbose = prefix_verbose or _("Related object")
limit_content_type_choices_to = limit_content_type_choices_to
or {}

content_type_field = f"{p}content_type"
object_id_field = f"{p}object_id"
content_object_field = f"{p}content_object"

class TheClass(models.Model):
class Meta:
abstract = True

if add_related_name:
if not prefix:
raise FieldError("if add_related_name is set to "
"True, a prefix must be given")
related_name = prefix
else:
related_name = None

optional = not is_required

ct_verbose_name = _(f"{prefix_verbose}'s type (model)")

content_type = models.ForeignKey(
ContentType,
verbose_name=ct_verbose_name,
related_name=related_name,
blank=optional,
null=optional,
help_text=_("Please select the type (model) "
"for the relation, you want to build."),
limit_choices_to=limit_content_type_choices_to,
on_delete=models.CASCADE)

fk_verbose_name = prefix_verbose

object_id = models.CharField(
fk_verbose_name,
blank=optional,
null=False,
help_text=_("Please enter the ID of the related object."),
max_length=255,
default="") # for migrations

content_object = GenericForeignKey(
ct_field=content_type_field,
fk_field=object_id_field)

TheClass.add_to_class(content_type_field, content_type)
TheClass.add_to_class(object_id_field, object_id)
TheClass.add_to_class(content_object_field, content_object)

return TheClass
  1. The following code snippet is an example of how to use two generic relationships in your app (put this code in ideas/models.py):
# myproject/apps/ideas/models.py
from django.db import models
from django.utils.translation import gettext_lazy as _

from myproject.apps.core.models import (
object_relation_base_factory as generic_relation,
)


FavoriteObjectBase = generic_relation(
is_required=True,
)


OwnerBase = generic_relation(
prefix="owner",
prefix_verbose=_("Owner"),
is_required=True,
add_related_name=True,
limit_content_type_choices_to={
"model__in": (
"user",
"group",
)
}
)


class Like(FavoriteObjectBase, OwnerBase):
class Meta:
verbose_name = _("Like")
verbose_name_plural = _("Likes")

def __str__(self):
return _("{owner} likes {object}").format(
owner=self.owner_content_object,
object=self.content_object
)

How it works...

As you can see, this snippet is more complex than the previous ones.

The object_relation_base_factory function, which we have aliased to generic_relation, for short, in our import, is not a mixin itself; it is a function that generates a model mixin – that is, an abstract model class to extend from. The dynamically created mixin adds the content_type and object_id fields and the content_object generic foreign key that points to the related instance.

Why can't we just define a simple model mixin with these three attributes? A dynamically generated abstract class allows us to have prefixes for each field name; therefore, we can have more than one generic relation in the same model. For example, the Like model, which was shown previously, will have the content_type, object_id, and content_object fields for the favorite object, and owner_content_type, owner_object_id, and owner_content_object for the one (user or group) that liked the object.

The object_relation_base_factory function, which we have aliased
to generic_relation for short, adds the possibility to limit the content type choices by the limit_content_type_choices_to parameter. The preceding example limits the choices for owner_content_type to only the content types of the User and Group models.

See also

  • The Creating a model mixin with URL-related methods 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 Implementing the Like widget recipe in Chapter 4, Templates and JavaScript

Create a Note

Modal Close icon
You need to login to use this feature.
notes
bookmark search playlist download font-size

Change the font size

margin-width

Change margin width

day-mode

Change background colour

Close icon Search
Country selected

Close icon Your notes and bookmarks

Delete Bookmark

Modal Close icon
Are you sure you want to delete it?
Cancel
Yes, Delete

Delete Note

Modal Close icon
Are you sure you want to delete it?
Cancel
Yes, Delete

Edit Note

Modal Close icon
Write a note (max 255 characters)
Cancel
Update Note

Confirmation

Modal Close icon
claim successful

Buy this book with your credits?

Modal Close icon
Are you sure you want to buy this book with one of your credits?
Close
YES, BUY