Singleton design pattern example: Singleton models in Django
To simplify the communication between developers, each recommendation has a name of its own - Singleton, Observer, etc. Such an approach is particularly useful, because irrespective of a language used by a programmer, an abstract task has an abstract solution clear for those familiar with Design Patterns.
In this article, we are taking a look at one of design patterns, namely Singleton. Our purpose is to implement this pattern in Python in order to use it in Django project.
So, what is Singleton design pattern?
As it is written in the book “Design Patterns: Elements of Reusable Object-Oriented Software” by Gang of Four:
The singleton pattern is a design pattern that is used to ensure that a class can only have one concurrent instance. Whenever additional objects of a singleton class are required, the previously created, single instance is provided.
This is the class that controls the process of its instantiation by itself, hiding a usual constructor, and offers a method for obtaining an instance instead. The first time this method is called, an instance of a class is created, which is returned for all subsequent method calls.
This is one of the most simple design patterns, but not the least useful. Most of the times it is used to coordinate the whole system. It can be a settings object, a connection object or session object, etc. What is important in this case is that at any moment we cannot have more than one Singleton object.
At first glance it may seem easier to use global variables, but it’s misleading. Although global variables don’t require the implementation of a special instantiation mechanism like Singleton, they are also less reliable. For example, if you store a lot of settings in global variables, then the probability of names conflicts increases, especially so when writing the library which is going to be used in other projects.
It won’t be better if an instance of a class is stored in the global variable. Yes, there will be one globally available instance and, at first glance, it isn’t any different from a singleton, but in this case the instantiation of a class is not limited in any way. Suppose we have a process configuration class. Everything goes well as long as it is used by accessing a global variable. However, everything can go wrong if the library user instantiates this settings class themselves and changes some of its properties either by accident or due to the lack of knowledge. Most likely, its settings simply won’t be applied or will affect the part of the process. Debugging of such non-obvious mistakes may take up a lot of effort and time.
How to use singleton design pattern
The above mentioned problems could be avoided when using Singleton pattern. In most strongly-typed programming languages such as Java and C#, a singleton is implemented with the help of built-in tools of the language to restrict access and visibility. The idea is that the class constructor is declared as private or protected, and the class is added with the public static method (usually known as instance()), which calls this constructor in the first call and always returns one and the same instance of a class.
In Python almost all properties and methods are public, therefore the classic approach can’t be used. At Stack Overflow you can see a small selection of recipes for implementing a singleton in Python (there are indeed some elegant and interesting solutions among them!). To put it simply, we just use a simple class method, calling the standard constructor if necessary.
Using Django singleton model
Although you can use singletons in the form of ordinary classes in Django applications, let’s take a look at the implementation of a singleton as a model which allows you to save the internal state of the singleton in the database. In our singleton design pattern example, we will show how to implement some project settings in such a way that they can be changed in the admin panel and can be used in templates.
This example can be used in a production environment if there are few such settings or if some business logic is implied in this model. Otherwise, a ready-made solution should be used. For example, there is this great, popular and well-maintained Django application — Constance
To begin with, we declare the base class for our singleton model in django:
When you call load method, an object will be loaded from a database or, if the object does not exist in a database, it will be created. When you save an instance of the model, it always has the same primary key, so there is only one record for this model in the database. Thus, in order to create a class responsible for site settings, we will create a class based on an abstract SingletonModel.
This is a base class for Singleton model. When you call load method, an object will be loaded from a database or, if the object does not exist in a database, it will be created. So, in order to create a class responsible for site settings we will create a class based on an abstract SingletonModel.
To be able to edit settings we should register a model in django admin panel
Now we can use created settings object in the following way:
When we use load method, an object will be taken from a database, and in case it was not created yet, it will be added to a database with default values. Thus, to get a working application from the start, we have to specify default values in settings or add blank=True, null=True attributes and to process such exceptions further.
From Python’s perspective it is not yet a singleton, because every call load() will create a new object in the memory. However, since each one of them refers to the same record in the database, users of the singleton model are satisfied with it.
To be able to use data from settings in the pattern, you can add an object of settings either in context of view or context processor.
context_processors.py
Now let’s connect context process to settings.py:
After this we can use our settings in templates in the following way:
To reduce the amount of database requests, you can save settings to cache. For this let’s add method set_cache to the model.
Let’s update save and load methods:
Conclusion
We hope that now you know a bit more about a fascinating world of design patterns in Python, having read the information about the Singleton design pattern. Also, we applied the singleton pattern to web applications and implemented Django singleton model for storing some of project's frequently used settings, added settings context processors, optimized settings to reduce database requests using standard caching.
We received the answers on how exactly to implement configurable settings via admin panel and how to solve such problems.
The final code is available on Github.com.