Делается в два действия:
Во-первых,
в
models.py переопределяем метод
save()
для нашей модели
TbTemplate
. Заодно можем переопределить метод
delete()
, чтобы он ничего не удалял (или наоборот удалял не только запись в БД но и соответствующий файл... или удалял запись в БД, а соответствующий файл переименовывал...). Получим такую модель:
# -*- coding: utf-8 -*-
from django.db import models
from my_app.settings import *
class TbTemplate(models.Model):
""" Шаблоны """
szFileName = models.CharField(
primary_key=True,
db_index=True,
unique=True,
verbose_name="Имя шаблона"
)
szJinjaCode = models.TextField(
verbose_name='Шаблон',
help_text='Код шаблона (jinja2)'
)
szDescription = models.CharField(
max_length=100,
verbose_name='Описание'
)
def __unicode__(self):
return f"{self.szFileName} ({self.szDescription})"
def __str__(self):
return self.__unicode__()
# переопределяем save() для записи шаблонов не только в ДБ, но и в файл
def save(self, *args, **kwargs):
with open(TEMPLATES_DIR / self.szFileName, "w+", encoding="utf-8") as tmplt_file:
tmplt_file.write(self.szJinjaCode)
super(TbTemplate, self).save(*args, **kwargs)
# TODO: для продакшн, возможно, нужно добавить "дёргание" touch_reload и "моргнуть" uWSGI
# переопределяем метод delete() (пока, не удаляется)
def delete(self, *args, **kwargs):
pass
# super(TbTemplate, self).delete(*args, **kwargs)
class Meta:
verbose_name = '[…Шаблон]'
verbose_name_plural = '[…Шаблоны]'
Теперь, при изменении и создании шаблона в базе создастся соответствующий файл...
Во-вторых,
в файле
admin.py при определении класса
admin.ModelAdmin
для управления моделью
TbTemplate
нужно переопределить метод
get_fields()
который отвечает за получения полей в форму админки (пришлось искать метод тупо пробуя кучу схожих которые делают что-то похожее, но не то). В результате получаем примерно вот такой вот
admin.py:
# -*- coding: utf-8 -*-
from django.contrib import admin
from web.models import TbTemplate
from my_app.settings import *
class AdminTemplate(admin.ModelAdmin):
search_fields = ['szFileName', 'szDescription', 'szJinjaCode']
list_display = ('szFileName', 'szDescription')
list_display_links = ('szFileName', 'szDescription', )
empty_value_display = '<b style=\'color:red;\'>—//—</b>'
actions_on_top = False
actions_on_bottom = True
def get_fields(self, request, obj=None):
try:
with open(Path(TEMPLATES_DIR) / obj.szFileName, "r", encoding="utf-8") as template:
obj.szJinjaCode = template.read()
except (AttributeError, FileNotFoundError, TypeError):
pass
return ['szFileName', 'szDescription', 'szJinjaCode']
admin.site.register(TbTemplate, AdminTemplate)
Теперь, если какие-то внешние силы изменят файл шаблона (или кто-то поменяет код шаблона в БД в обход админки) , то при открытии шаблона на редактирование из админке, данные будут получены из файла.
Все.
UPD: в
settnig.py проекта надо добавить что-то типа:
TEMPLATES_DIR = BASE_DIR / 'templates-jinja2'
Чтоб модель и админка знали в какой каталог лить файлы шаблонов.