22.11.2019       Выпуск 309 (18.11.2019 - 24.11.2019)       Статьи

Django. Создание динамических настроек сайта с помощью SingletonModel

Допустим, вы создаёте сайт с CMS на основе Django, у которого должны быть какие-то динамические настройки сайта, которые будут доступны пользователю. Например, название сайта, какая-то специализированная информация, при этом вы учитываете возможность мультиязычности. То что тогда можно использовать для этого? Мне пришла мысль использовать базу данных.

Для реализации этого требуется следующее:

  1. Создание модели данных, которая всегда будет содержать только один объект, то есть только одну запись. То есть это будет Singleton Model.
  2. Запретить удалять данную запись и создавать новые в панели администрирования Django
  3. Возможность использования иноформации из этой модели прямо в шаблоне, без загрузки настроек сайта в view функции.

Давайте разберёмся по порядку, как это реализовать.

 

Читать>>




Экспериментальная функция:

Ниже вы видите текст статьи по ссылке. По нему можно быстро понять ссылка достойна прочтения или нет

Просим обратить внимание, что текст по ссылке и здесь может не совпадать.

Допустим, вы создаёте сайт с CMS на основе Django, у которого должны быть какие-то динамические настройки сайта, которые будут доступны пользователю. Например, название сайта, какая-то специализированная информация, при этом вы учитываете возможность мультиязычности. То что тогда можно использовать для этого? Мне пришла мысль использовать базу данных.

Для реализации этого требуется следующее:

  1. Создание модели данных, которая всегда будет содержать только один объект, то есть только одну запись. То есть это будет Singleton Model.
  2. Запретить удалять данную запись и создавать новые в панели администрирования Django
  3. Возможность использования иноформации из этой модели прямо в шаблоне, без загрузки настроек сайта в view функции.

Давайте разберёмся по порядку, как это реализовать.

1. SingletonModel

Я нашёл на GitHub код абстрактной SingletonModel, который был написан ещё в 2012 году. Вот ссылка на gist .

Вот программный код данной SingletonModel

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

    def save(self, *args, **kwargs):
        self.__class__.objects.exclude(id=self.id).delete()
        super(SingletonModel, self).save(*args, **kwargs)

    @classmethod
    def load(cls):
        try:
            return cls.objects.get()
        except cls.DoesNotExist:
            return cls()

Модель в методе save при сохранении объекта автоматически удаляет все остальные, что позволяет держать в базее данных всегда только один экземпляр данной модели.

Метод load берёт из базы данных то единственный объект настроек, если же объект не существует в базе данных, то возвращает новый инстанс этой модели, который нужно будет потом сохранить.

Создадим кастомный класс настроек, чтобы в дальнейшем использовать его для наших нужд.

# -*- coding: utf-8 -*-

from django.db import models
from django.utils.translation import ugettext_lazy as _

from my_app.singleton_model import SingletonModel


class SiteSettings(SingletonModel):
    site_url = models.URLField(verbose_name=_('Website url'), max_length=256)
    title = models.CharField(verbose_name=_('Title'), max_length=256)

    def __str__(self):
        return 'Configuration'

2. Настройка панели администрирования

Теперь нужно запретить удалять данную запись и создавать новые в панели администрирования Django.

# -*- coding: utf-8 -*-

from django.contrib import admin
from django.db.utils import ProgrammingError

from my_app.models import SiteSettings


class SiteSettingsAdmin(admin.ModelAdmin):
    # Создадим объект по умолчанию при первом страницы SiteSettingsAdmin со списком настроек
    def __init__(self, model, admin_site):
        super().__init__(model, admin_site)
        # обязательно оберните загрузку и сохранение SiteSettings в try catch,
        # чтобы можно было выполнить создание миграций базы данных
        try:
            SiteSettings.load().save()
        except ProgrammingError:
            pass

    # запрещаем добавление новых настроек
    def has_add_permission(self, request, obj=None):
        return False

    # а также удаление существующих
    def has_delete_permission(self, request, obj=None):
        return False


admin.site.register(SiteSettings, SiteSettingsAdmin)

Теперь настройки можно использовать в Python коде

3. Создание context processor для загрузки настроек в шаблон

context_proccessors.py

# -*- coding: utf-8 -*-

from evileg_settings.models import SiteSettings


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

settings.py

После чего подключаем load_settings

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                # Загружаем наши настройки при каждом рендеринге шаблона с контекстом
                'my_app.context_processors.load_settings', 
            ],
        },
    },
]

Использование в шаблоне

<h1>{{ site_settings.title }}</h1>

Заключение

Вот так быстро и просто можно внедрить в Django простые динамические настройки сайта и потом привязывать их ко все интересующим нас параметрам сайта.
Преимуществом такого подхода будет возможность использования внешних ключей на какие-то специальные данные на сайта, а также использование django modeltranslation, а значит не будет проблем с мультиязычностью.






Разместим вашу рекламу

Пиши: mail@pythondigest.ru

Нашли опечатку?

Выделите фрагмент и отправьте нажатием Ctrl+Enter.

Система Orphus