CodeMirror.multiplexingMode
. Причем последовательно для каждой пары открывающий/закрывающий тег. Таким образом для смешивания html+jinja2 в админке Django получится вот такой /static/js/codemirror/init_jinja2.js
:// Этот файл нужен для инициализации html+jinja-редактора шаблонов codemirror в админке Django
// рецепт написал сам: https://qna.habr.com/q/1284408
(function () {
var $ = django.jQuery;
$(document).ready(function () {
// Включаем "темную" или "светлую" тему в зависимости от настроек браузера пользователя
var theme_is = 'idea';
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) theme_is = 'rubyblue'; // dark mode
// Включаем подсветку jinja-тегов {{...}} внутри html
CodeMirror.defineMode("html+jinja2{}", function (config) {
return CodeMirror.multiplexingMode(
CodeMirror.getMode(config, "text/html"), {
open: "{{", close: "}}",
mode: CodeMirror.getMode(config, "jinja2"),
parseDelimiters: true,
}
);
});
// Включаем подсветку jinja2-тегов {%...%}
CodeMirror.defineMode("html+jinja2%%", function (config) {
return CodeMirror.multiplexingMode(
CodeMirror.getMode(config, "html+jinja2{}"), {
open: "{%", close: "%}",
mode: CodeMirror.getMode(config, "jinja2"),
parseDelimiters: true,
}
);
});
// Включаем подсветку jinja2-комментариев {#...#}
CodeMirror.defineMode("html+jinja2", function (config) {
return CodeMirror.multiplexingMode(
CodeMirror.getMode(config, "html+jinja2%%"), {
open: "{#", close: "#}",
mode: CodeMirror.getMode(config, "jinja2"),
parseDelimiters: true,
}
);
});
// инициализация codemirror
$('#code_editor').each(function (idx, el) {
var editor = CodeMirror.fromTextArea(el, {
lineNumbers: true,
tabSize: 2,
mode: 'html+jinja2',
gutters: ['CodeMirror-lint-markers'],
theme: theme_is,
lint: true,
autoCloseTags: true,
matchBrackets: true,
});
editor.setSize('120em', 'auto');
editor.addKeyMap({
'Ctrl-S': function (cm) {$(el).closest('form').submit(); }, // submit
'Ctrl-F': 'findPersistent', // поиск
});
});
});
})();
pip install mysqlclient
проходит, а в терминале PyCharm падает.snap install --classic pycharm-professional
sudo apt-get install mariadb-client libmariadb3 libmariadb-devel python3-dev gcc
pip install mysqlclient
Collecting mysqlclient
Using cached mysqlclient-2.2.0.tar.gz (89 kB)
Installing build dependencies ... done
Getting requirements to build wheel ... done
Installing backend dependencies ... done
Preparing metadata (pyproject.toml) ... done
Building wheels for collected packages: mysqlclient
Building wheel for mysqlclient (pyproject.toml) ... done
Created wheel for mysqlclient: filename=mysqlclient-2.2.0-cp39-cp39-linux_x86_64.whl size=132574 sha256=c166b260e0fc2a846d40df5af021b1a8bd5e5507348571c2f4df23086d01dd26
Stored in directory: /home/___/.cache/pip/wheels/aa/58/d4/2e7a1d266508fd74887c2f74ec1ae819509bae6711480d8666
Successfully built mysqlclient
Installing collected packages: mysqlclient
Successfully installed mysqlclient-2.2.0
'D:\\export\\'
'D:/export/'
filename.replace('\\', '/').split('/')
re.split( r'[\\/]', filename)
os.path.normpath(path).split(os.sep)
q_filial = TbPeople.objects.raw("SELECT DISTINCT web_tbpeople.szFilial, 1 AS id "
"FROM web_tbpeople ORDER BY web_tbpeople.szFilial;")
szID
и это строковая переменная. Таким образом для моего случая рабочий код вот такой:q_filial = TbPeople.objects.raw("SELECT DISTINCT web_tbpeople.szFilial, '1' AS szID "
"FROM web_tbpeople ORDER BY web_tbpeople.szFilial;")
q_filial = TbPeople.objects.raw("SELECT DISTINCT web_tbpeople.szFilial AS szID"
"FROM web_tbpeople;")
brew install mariadb-connector-c
source ~/path-to-project-enveroment/bin/activate
pip install mysqlclient
# выключаем окружение отключаем системный коннектор (можно не делать)
deactivate
brew unlink mariadb-connector-c
xcode-select --install
m1
, но проверка через Python показывает:import socket
socket.gethostname()
'm1.N1'
'm1.local'
(и для этого не надо перезагружаться, достаточно просто чтоб компьютер перешел в режим сна... хотя х.з. ... в macOS гибридный режим сна, и если во время сна перегружается по питанию, внешне это никак не заметно). В общем, это странное поведение hostname тоже попортило немного крови. :) 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.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)
TEMPLATES_DIR = BASE_DIR / 'templates-jinja2'