Evgenii Legotckoi
22 ноября 2019 г. 13:03

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

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

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

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

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


SingletonModel

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

Вот код для этой SingletonModel

  1. class SingletonModel(models.Model):
  2. class Meta:
  3. abstract = True
  4.  
  5. def save(self, *args, **kwargs):
  6. self.__class__.objects.exclude(id=self.id).delete()
  7. super(SingletonModel, self).save(*args, **kwargs)
  8.  
  9. @classmethod
  10. def load(cls):
  11. try:
  12. return cls.objects.get()
  13. except cls.DoesNotExist:
  14. return cls()

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

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

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

  1. # -*- coding: utf-8 -*-
  2.  
  3. from django.db import models
  4. from django.utils.translation import ugettext_lazy as _
  5.  
  6. from my_app.singleton_model import SingletonModel
  7.  
  8.  
  9. class SiteSettings(SingletonModel):
  10. site_url = models.URLField(verbose_name=_('Website url'), max_length=256)
  11. title = models.CharField(verbose_name=_('Title'), max_length=256)
  12.  
  13. def __str__(self):
  14. return 'Configuration'

Настройка панели администратора

Теперь нужно запретить удаление этой записи и создание новых в админке Django.

  1. # -*- coding: utf-8 -*-
  2.  
  3. from django.contrib import admin
  4. from django.db.utils import ProgrammingError
  5.  
  6. from my_app.models import SiteSettings
  7.  
  8.  
  9. class SiteSettingsAdmin(admin.ModelAdmin):
  10. # Create a default object on the first page of SiteSettingsAdmin with a list of settings
  11. def __init__(self, model, admin_site):
  12. super().__init__(model, admin_site)
  13. # be sure to wrap the loading and saving SiteSettings in a try catch,
  14.         # so that you can create database migrations
  15. try:
  16. SiteSettings.load().save()
  17. except ProgrammingError:
  18. pass
  19.  
  20. # prohibit adding new settings
  21. def has_add_permission(self, request, obj=None):
  22. return False
  23.  
  24. # as well as deleting existing
  25. def has_delete_permission(self, request, obj=None):
  26. return False
  27.  
  28.  
  29. admin.site.register(SiteSettings, SiteSettingsAdmin)
  30.  

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

Создание контекстного процессора для загрузки настроек в шаблон

context_proccessors.py

  1. # -*- coding: utf-8 -*-
  2.  
  3. from evileg_settings.models import SiteSettings
  4.  
  5.  
  6. def load_settings(request):
  7. return {'site_settings': SiteSettings.load()}
  8.  

settings.py

Затем подключаем load_settings

  1. TEMPLATES = [
  2. {
  3. 'BACKEND': 'django.template.backends.django.DjangoTemplates',
  4. 'DIRS': [],
  5. 'APP_DIRS': True,
  6. 'OPTIONS': {
  7. 'context_processors': [
  8. 'django.template.context_processors.debug',
  9. 'django.template.context_processors.request',
  10. 'django.contrib.auth.context_processors.auth',
  11. 'django.contrib.messages.context_processors.messages',
  12. # Загружаем наши настройки при каждом рендеринге шаблона с контекстом
  13. 'my_app.context_processors.load_settings',
  14. ],
  15. },
  16. },
  17. ]

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

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

Вывод

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

Вам это нравится? Поделитесь в социальных сетях!

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь