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

Django, SingletonModel, singleton, Model

Содержание

Допустим, вы создаёте сайт с 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, а значит не будет проблем с мультиязычностью.

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.
- блог компании
Поддержать автора Donate

Комментарии

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

Здравствуйте, уважаемые пользователи EVILEG !!!

Если сайт вам помог, то поддержите разработку сайта финансово, пожалуйста.

Вы можете сделать это следующими способами:

Спасибо, Евгений Легоцкой

v
9 апреля 2020 г. 5:41
vitalisimys

Qt - Тест 001. Сигналы и слоты

  • Результат:21баллов,
  • Очки рейтинга-10
v
9 апреля 2020 г. 5:36
vitalisimys

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:40баллов,
  • Очки рейтинга-8
v
9 апреля 2020 г. 5:32
vitalisimys

C++ - Тест 001. Первая программа и типы данных

  • Результат:53баллов,
  • Очки рейтинга-4
Последние комментарии
8 апреля 2020 г. 9:12
ogustbiller

Круто! Немного начинает проясняться что к чему. Спасибо.
K
7 апреля 2020 г. 8:55
KULINAR847

А вот уже и на python... #!/usr/bin/env python# -'''- coding: utf-8 -'''-import sysfrom PySide2.QtWidgets import *from PySide2.QtQuick import *from PySide2.QtCore import *from PySide2.…
3 апреля 2020 г. 8:06
Konstantin Grudnitskiy

Я надеюсь вы уже разобрались в чем дело, но если вдруг нет, то проблема состоит в том, что вы пытаетесь запустить программу из интерпретатора питона. Файл main.py это уже готова…
3 апреля 2020 г. 6:18
Konstantin Grudnitskiy

>>> text = 'hello world'>>> ' '.join(word for word in text.split()[:-1])'hello'>>> def remove_last_word(text):... return text and ' '.join(word for word in text.s…
27 марта 2020 г. 14:40
Евгений Легоцкой

Добрый день. В конце пятой статьи скачать можете.
Сейчас обсуждают на форуме
ДК
9 апреля 2020 г. 3:31
Джон Кофи

Привет. Делаю реализацию перемещения строк на QTableView с моделью QSqlTableModel. Буду в этой теме спрашивать нужное. Пока такой вопрос при создании модели: как мне узнать rowCount? int…
8 апреля 2020 г. 17:42
elyana

Подскажите как правильно реализовать... Нужно создать массив в C++ с переменными типа сhar или же int. В Qml будет переменная, например text, которая будет изменять своё значение в зависим…
ДК
8 апреля 2020 г. 6:29
Джон Кофи

:-D блин, без слов, пойду пройдусь))
s
8 апреля 2020 г. 4:59
slava_d2000

Всем привет. Прошу помощи.есть статическая сборка 5.14.2 (без SSL) компилируется чистый шаблон на QML и Widgets если войти на компьютер в терминальной сессии и запустить программ…
s
6 апреля 2020 г. 8:06
shuric

Добрый день. Объясните пожалуйста ... ... допиливать стилевое оформление в прокси классе ... где именно копать ? В каком виртуальном методе лучше допиливать (если можно н…
EVILEG
О нас
Услуги
© EVILEG 2015-2019
Рекомендует хостинг TIMEWEB