Generic Relations and Pluggable Apps

Learn via video courses
Topics Covered

Overview

Generic relations are the special relation type that is supported by Django which allows relationships not to be bounded by one particular model. A general Foreign Key is allowed to point to one model only, Special type of field i.e. GenericForeignKey is provided by the contenttypes application which allows the relationship of the model with any model available in the particular Django application.

What are Generic Relations?

Generic relations are the special relation type that is supported by Django which allows relationships not to be bounded by one particular model. So generic relation enables to have a relationship that is handling cases such as follows and likes in social media apps, and where a group, person, page or post can be followed or liked with a minimal amount of coding.

How to Use Generic Relation?

We are creating the model with the name TaggedItem for the Tagging System and here we are using a generic relation:

A general Foreign Key is allowed to point to one model only, this means that if there is a foreign key in the TaggedItem then for storing tags we have to select one model only. A special type of field i.e. GenericForeignKey is provided by the content types application which allows the relationship of the model with any model available in the particular Django application.

The GenericForeignKey class has the following three parts:

  • In your model TaggedItem and make a foreign key field to the ContentType having the name content_type
  • In your model, make a field that will be able to save the values of the primary key from the model you are related to. It is considered a PositiveIntergerField in almost all models. object_id is considered the common name for this particular field.
  • Provide a GenericForeignKey to your model. And then pass the above two mentioned fields in it. If the names of these fields are content_type and object_id, then you are allowed to omit the name of these fields. As the above-mentioned names are the names of the default fields.

Indexes are not created automatically for the GenericForeignKey. So use the Meta.indexes for multiple-column index creation.

Reverse Relations

By default, there is no existence of the relation on the related object back to this object. For the creation of related object relation creation back to this object we need to set the related_query_name. Filtering and querying from the related object are enabled by it. If you are familiar with the model which is often used then, your "reverse” generic relationship addition can be done to enable an extra API.

For example:

We are creating a model with the name Bookmark, having the Generic Relation with the TaggedItem

Each Bookmark instance has a tags attribute and can utilize these attributes in getting their specific TaggedItem.

For relationship creation, set(), create() or add() can be used.

To delete the specified model objects in bulk, use the remove () call.

Querying from the related object is enabled by the GenericRelation definition with the related_query_name set

Ordering, Filtering and many more query operations from the TaggedItem on Bookmark are enabled by it.

Similar to the GenericForeignKey, GenericRelation accepts arguments in the form of the object-ID and content-type fields. If the object having GenericRelation is deleted, then there is a deletion of all the objects which have GenericForeignKey which is pointed by it.

Caveats

Caveats are considered as one of the Generic relations and ContentTypes usages. Another caveat is that for behaviour customization, the on_delete argument is not accepted by the GenericForeignKey. All the relations are cascaded by the default behaviour. Do not define the GenericRelation is considered to be as one solution to avoid the default behaviour.

Implementing ContentType class provides the facility to generate the list of likes that are received by this particular Comment.

Features of Plugable Apps

  • It is possible to install it from anywhere on the path of Python, just by implementing "pip install package-name".
  • There is no need for the site to have some explicit knowledge of the app like what directories the particular app has. (It is not mandatory to add up the install directory of the app in the settings or something similar with it).
  • All the available functions of the site will not be broken, if you want to perform the installation and configuration process of the app.
  • For upgrading the app, we only need to install the new version of the app. (It is also possible that the site has to implement some changes so that it can take advantage of the new version of the app having more features. But features are added to an ideal app without any modification in the behavior of the existing feature).
  • Apps Upgradation and Installation doesn't need to copy files or some part of code or its documentation.
  • There is no need to fork the code to customize the app.

How to Write Reusable Apps?

Reusability Matters

In python, reusability is considered a way of life. A wide range of packages is provided by the Python Package Index (PyPI) which can be used by you in your programs of python. Itself Django is also one of the normal packages of python. This means it allows you to take Django apps or existing packages of Django and allows them to compose in your project. And only writing the code of the parts is required for making your project unique.

Your Project and Your Reusable App

The directory of any project can be copied and pasted into any new project of Django and can be reused immediately but it is not ready for the published. For publishing purposes packaging of the app is required to make its installation easy for others.

Installing Some Prerequisites

For our package building, here we are going to use the setup tools. And for installing and uninstalling it we are going to use the pip.

Packaging Your App

App preparation in a format that can be used and installed easily is referred to as Python packaging. Here we take an example of the app created with the name test.

  1. First step is to parent directory creation for the test, and this is created outside of your project. And assign the django-test name to this directory
  2. And now move the test directory to the directory with the name django-test directory.
  3. Now inside the django-test create a file with the name README.rst(django-test/README.rst) and this contains the description of your model.
  4. Now create the file django-test/LICENSE. The code is useless if it is released publicly without any license. And you are free for your license selection. And the code used by whom is affected by the choice of your license.
  5. For detailing the app building and installation we will create three files with the name setup.cfg, pyproject.toml and setup.py
  1. By default only packages and modules of python are included in the package. It is required to create a file with the name MANIFEST.in file for including additional files.
  1. For the documentation of the app create an empty directory with the name django-test/docs. And including the detailed documentation of the app is optional but it is recommended to include it. For including it simply adds the line given below in the MANIFEST.in file:
  1. Run the command python setup.py sdist inside the django-test for your package building. A directory with the name dist is created by it and a new package is built by it, django-test-0.1.tar.gz.

Using Your Package

Since we moved the Tets directory out of the project, it’s no longer working. We’ll now fix this by installing our new django-test package.

  1. For package installation use the pip:
  1. Now our project is working correctly. For confirming this run your server again.

  2. For package uninstallation, use the pip command and write the command written below:

Publishing Your App

As testing and packaging of the django-test have been done, now it can be shared with the world. The package can be mailed, uploaded and can be posted on a public repository.

Conclusion

  • Generic relations are the special relation type that is supported by Django which allows relationships not to be bounded by one particular model.
  • A special type of field i.e. GenericForeignKey is provided by the contenttypes application which allows the relationship of the model with any model available in the particular Django application.
  • Indexes are not created automatically for the GenericForeignKey. So use the Meta.indexes for multiple-column index creation.
  • For the creation of related object relation creation back to this object we need to set the related_query_name.
  • Caveats are considered as one of the Generic relations and ContentTypes usages.