OUR Blog
Python developer
Arthur Shevchenko
Python developer
PYTHON/DJANGO
May 04 2016

Singleton Design Pattern Example

Today there is a huge number of software development methodologies - TDD, BDD, Scrum, etc. Part of them refers to development process, another part to development management, and there are also methodologies defining which code to use in this or that case. One of these high-level methodologies is design pattern. This methodology is a set of some agreements and recommendations on code writing in certain situations, irrelevant to a programming language.

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:

from django.db import models

class SingletonModel(models.Model):

    class Meta:
        abstract = True

    def save(self, *args, **kwargs):
        self.pk = 1
        super(SingletonModel, self).save(*args, **kwargs)

    def delete(self, *args, **kwargs):
        pass

    @classmethod
    def load(cls):
        obj, created = cls.objects.get_or_create(pk=1)
        return obj

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.

class SiteSettings(SingletonModel):
    support = models.EmailField(default='support@example.com')
    sales_department = models.EmailField(blank=True)
    twilio_account_sid = models.CharField(max_length=255, default='ACbcad883c9c3e9d9913a715557dddff99')
    twilio_auth_token = models.CharField(max_length=255, default='abd4d45dd57dd79b86dd51df2e2a6cd5')
    twilio_phone_number = models.CharField(max_length=255, default='+15006660005')

To be able to edit settings we should register a model in django admin panel:

from django.contrib import admin
from .models import SiteSettings

admin.site.register(SiteSettings)

Now we can use created settings object in the following way:

from .models import SiteSettings

settings = SiteSettings.load()

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

from .models import SiteSettings

def settings(request):
    return {'settings': SiteSettings.load()}

Now let’s connect context process to settings.py:

TEMPLATES = [
    {
    ... 
        'OPTIONS': {
        ...
            'context_processors': [
                'common.context_processors.settings',
            ...
            ],
        },
    },
]

After this we can use our settings in templates in the following way:

Support: {{ settings.support }}
{% if settings.sales_department %}
Sales Department: {{ settings.sales_department }}
{% endif %}

To reduce the amount of database requests, you can save settings to cache. For this let’s add method set_cache to the model.

from django.core.cache import cache


class SingletonModel(models.Model):
...
    def set_cache(self):
        cache.set(self.__class__.__name__, self)

Let’s update save and load methods:

class SingletonModel(models.Model):
...
    def save(self, *args, **kwargs):
            self.pk = 1
            super(SingletonModel, self).save(*args, **kwargs)
        self.set_cache()

    @classmethod
    def load(cls):
        if cache.get(cls.__name__) is None:
            obj, created = cls.objects.get_or_create(pk=1)
            if not created:
                obj.set_cache()
        return cache.get(cls.__name__)

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.

Useful links

  1. Good singleton pattern recipes for Python on Stack Overflow
  2. Constance -- Django settings configurable in admin panel
  3. Wikipedia page about "Design Patterns" book
WHAT CLIENTS SAY ABOUT STEELKIWI
SIMILAR POSTS
May 08 2017
In this article you will find a list of 17 best Python web frameworks to learn in 2017.
Mar 28 2017
Learn: when is the right time for writing unit tests and what are their advantages? How they can help in the development process.
Jan 05 2017
Implementing websocket server into Django project using aiohttp and redis PUB/SUB.