Переехал с 1cpp. Ссылку публиковать не буду, форум умер :(
Приветствую коллеги!
Потихоньку разрабатываю замену платформы 1С 7.7 + 1cpp. Пока исключительно для себя и компании в которой работаю.
Успешно получалось долгое время обходить все болячки и технические долги во многом очень удачной платформы. Но в итоге уткнулся таки в ограничения. Переход на 8 - привел бы к таким-же последствиям.
Основным фактором, как это не странно, стал постепенный переход на Битрикс24. Пользователи активно начали работать с браузером. Понадобились синхронизации (выгрузки - загрузки), чтобы исключить двойную работу. Не считая установки двух мониторов, чтобы удобнее было работать в 1С и в Битрикс... Ну и массу других вещей...
Короче захотелось странного.
1. Нужен был оперативный конструктор, позволяющий редактировать структуру справочников и документов на лету.
2. Нужны были сложные структуры данных - типа деревьев, словарей (составных реквизитов), в том числе и в документах.
3. Нужны были документы с контролем ошибок, до того момента ,как это попадет в базу...
4. Все действия пользователя с данными - должны быть в истории, и это было свойством платформы на любых уровнях.
5. Чтобы кода поменьше.
6. Расширений и библиотек побольше.
7. JavaScript для управления формами.
8. И все это в браузере...
Короче.
Вроде бы концепт получился...
Разработка еще займет кучу времени.
Идей еще много, чтобы включить это в платформу, но пока могу дать первую версию, на которой уже можно сделать очень много.
Ссылка на проект тут
https://github.com/fobyphill/forTea
Недавно обновил проект.
Документация отстает - как обычно.
Что с многопользовательской работой? что с блокировками/транзакциями?
насколько я понимаю - установка неуспешно
ModuleNotFoundError: No module named 'distutils'
Launch unsuccessful. Exiting.
Для продолжения нажмите любую клавишу . . .
python
E:\00\venv
""
Creating venv in directory E:\00\venv using python "D:\Program Files\python.exe"
Install requirements to venv
activate
start pip
Unable to install requirements
exit code: 2
stdout:
Collecting asgiref==3.5.0 (from -r requirements.txt (line 1))
Using cached asgiref-3.5.0-py3-none-any.whl.metadata (9.2 kB)
Collecting backports.zoneinfo==0.2.1 (from -r requirements.txt (line 2))
Using cached backports.zoneinfo-0.2.1.tar.gz (74 kB)
Installing build dependencies: started
Installing build dependencies: finished with status 'done'
Getting requirements to build wheel: started
Getting requirements to build wheel: finished with status 'done'
Preparing metadata (pyproject.toml): started
Preparing metadata (pyproject.toml): finished with status 'done'
Collecting certifi==2021.10.8 (from -r requirements.txt (line 3))
Using cached certifi-2021.10.8-py2.py3-none-any.whl.metadata (3.0 kB)
Collecting charset-normalizer==2.0.12 (from -r requirements.txt (line 4))
Using cached charset_normalizer-2.0.12-py3-none-any.whl.metadata (11 kB)
Collecting contourpy==1.0.7 (from -r requirements.txt (line 5))
Using cached contourpy-1.0.7.tar.gz (13.4 MB)
Installing build dependencies: started
Installing build dependencies: finished with status 'done'
Getting requirements to build wheel: started
Getting requirements to build wheel: finished with status 'done'
Preparing metadata (pyproject.toml): started
Preparing metadata (pyproject.toml): finished with status 'done'
Collecting cycler==0.11.0 (from -r requirements.txt (line 6))
Using cached cycler-0.11.0-py3-none-any.whl.metadata (785 bytes)
Collecting DateTime==4.4 (from -r requirements.txt (line 7))
Using cached DateTime-4.4-py2.py3-none-any.whl.metadata (32 kB)
Collecting Django==4.0.2 (from -r requirements.txt (line 8))
Using cached Django-4.0.2-py3-none-any.whl.metadata (4.0 kB)
Collecting fonttools==4.39.4 (from -r requirements.txt (line 9))
Using cached fonttools-4.39.4-py3-none-any.whl.metadata (146 kB)
Collecting idna==3.3 (from -r requirements.txt (line 10))
Using cached idna-3.3-py3-none-any.whl.metadata (9.8 kB)
Collecting importlib-resources==5.12.0 (from -r requirements.txt (line 11))
Using cached importlib_resources-5.12.0-py3-none-any.whl.metadata (4.1 kB)
Collecting kiwisolver==1.4.4 (from -r requirements.txt (line 12))
Using cached kiwisolver-1.4.4.tar.gz (97 kB)
Installing build dependencies: started
Installing build dependencies: finished with status 'done'
Getting requirements to build wheel: started
Getting requirements to build wheel: finished with status 'done'
Preparing metadata (pyproject.toml): started
Preparing metadata (pyproject.toml): finished with status 'done'
Collecting matplotlib==3.7.1 (from -r requirements.txt (line 13))
Using cached matplotlib-3.7.1.tar.gz (38.0 MB)
Installing build dependencies: started
Installing build dependencies: finished with status 'done'
Getting requirements to build wheel: started
Getting requirements to build wheel: finished with status 'done'
Preparing metadata (pyproject.toml): started
Preparing metadata (pyproject.toml): finished with status 'done'
Collecting mysqlclient==2.1.0 (from -r requirements.txt (line 14))
Using cached mysqlclient-2.1.0.tar.gz (87 kB)
Installing build dependencies: started
Installing build dependencies: finished with status 'done'
Getting requirements to build wheel: started
Getting requirements to build wheel: finished with status 'done'
Preparing metadata (pyproject.toml): started
Preparing metadata (pyproject.toml): finished with status 'done'
Collecting networkx==3.1 (from -r requirements.txt (line 15))
Using cached networkx-3.1-py3-none-any.whl.metadata (5.3 kB)
Collecting numpy==1.22.4 (from -r requirements.txt (line 16))
Using cached numpy-1.22.4.zip (11.5 MB)
Installing build dependencies: started
Installing build dependencies: finished with status 'done'
Getting requirements to build wheel: started
Getting requirements to build wheel: finished with status 'done'
stderr:
[notice] A new release of pip is available: 24.3.1 -> 25.0.1
[notice] To update, run: python.exe -m pip install --upgrade pip
ERROR: Exception:
Traceback (most recent call last):
File "E:\00\venv\Lib\site-packages\pip\_internal\cli\base_command.py", line 105, in _run_wrapper
status = _inner_run()
File "E:\00\venv\Lib\site-packages\pip\_internal\cli\base_command.py", line 96, in _inner_run
return self.run(options, args)
~~~~~~~~^^^^^^^^^^^^^^^
File "E:\00\venv\Lib\site-packages\pip\_internal\cli\req_command.py", line 67, in wrapper
return func(self, options, args)
File "E:\00\venv\Lib\site-packages\pip\_internal\commands\install.py", line 379, in run
requirement_set = resolver.resolve(
reqs, check_supported_wheels=not options.target_dir
)
File "E:\00\venv\Lib\site-packages\pip\_internal\resolution\resolvelib\resolver.py", line 95, in resolve
result = self._result = resolver.resolve(
~~~~~~~~~~~~~~~~^
collected.requirements, max_rounds=limit_how_complex_resolution_can_be
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "E:\00\venv\Lib\site-packages\pip\_vendor\resolvelib\resolvers.py", line 546, in resolve
state = resolution.resolve(requirements, max_rounds=max_rounds)
File "E:\00\venv\Lib\site-packages\pip\_vendor\resolvelib\resolvers.py", line 397, in resolve
self._add_to_criteria(self.state.criteria, r, parent=None)
~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\00\venv\Lib\site-packages\pip\_vendor\resolvelib\resolvers.py", line 173, in _add_to_criteria
if not criterion.candidates:
^^^^^^^^^^^^^^^^^^^^
File "E:\00\venv\Lib\site-packages\pip\_vendor\resolvelib\structs.py", line 156, in __bool__
return bool(self._sequence)
File "E:\00\venv\Lib\site-packages\pip\_internal\resolution\resolvelib\found_candidates.py", line 174, in __bool__
return any(self)
File "E:\00\venv\Lib\site-packages\pip\_internal\resolution\resolvelib\found_candidates.py", line 162, in <genexpr>
return (c for c in iterator if id(c) not in self._incompatible_ids)
^^^^^^^^
File "E:\00\venv\Lib\site-packages\pip\_internal\resolution\resolvelib\found_candidates.py", line 53, in _iter_built
candidate = func()
File "E:\00\venv\Lib\site-packages\pip\_internal\resolution\resolvelib\factory.py", line 187, in _make_candidate_from_link
base: Optional[BaseCandidate] = self._make_base_candidate_from_link(
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
link, template, name, version
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "E:\00\venv\Lib\site-packages\pip\_internal\resolution\resolvelib\factory.py", line 233, in _make_base_candidate_from_link
self._link_candidate_cache[link] = LinkCandidate(
~~~~~~~~~~~~~^
link,
^^^^^
...<3 lines>...
version=version,
^^^^^^^^^^^^^^^^
)
^
File "E:\00\venv\Lib\site-packages\pip\_internal\resolution\resolvelib\candidates.py", line 304, in __init__
super().__init__(
~~~~~~~~~~~~~~~~^
link=link,
^^^^^^^^^^
...<4 lines>...
version=version,
^^^^^^^^^^^^^^^^
)
^
File "E:\00\venv\Lib\site-packages\pip\_internal\resolution\resolvelib\candidates.py", line 159, in __init__
self.dist = self._prepare()
~~~~~~~~~~~~~^^
File "E:\00\venv\Lib\site-packages\pip\_internal\resolution\resolvelib\candidates.py", line 236, in _prepare
dist = self._prepare_distribution()
File "E:\00\venv\Lib\site-packages\pip\_internal\resolution\resolvelib\candidates.py", line 315, in _prepare_distribution
return preparer.prepare_linked_requirement(self._ireq, parallel_builds=True)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\00\venv\Lib\site-packages\pip\_internal\operations\prepare.py", line 527, in prepare_linked_requirement
return self._prepare_linked_requirement(req, parallel_builds)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "E:\00\venv\Lib\site-packages\pip\_internal\operations\prepare.py", line 642, in _prepare_linked_requirement
dist = _get_prepared_distribution(
req,
...<3 lines>...
self.check_build_deps,
)
File "E:\00\venv\Lib\site-packages\pip\_internal\operations\prepare.py", line 72, in _get_prepared_distribution
abstract_dist.prepare_distribution_metadata(
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
finder, build_isolation, check_build_deps
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "E:\00\venv\Lib\site-packages\pip\_internal\distributions\sdist.py", line 56, in prepare_distribution_metadata
self._install_build_reqs(finder)
~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^
File "E:\00\venv\Lib\site-packages\pip\_internal\distributions\sdist.py", line 126, in _install_build_reqs
build_reqs = self._get_build_requires_wheel()
File "E:\00\venv\Lib\site-packages\pip\_internal\distributions\sdist.py", line 103, in _get_build_requires_wheel
return backend.get_requires_for_build_wheel()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "E:\00\venv\Lib\site-packages\pip\_internal\utils\misc.py", line 701, in get_requires_for_build_wheel
return super().get_requires_for_build_wheel(config_settings=cs)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^
File "E:\00\venv\Lib\site-packages\pip\_vendor\pyproject_hooks\_impl.py", line 166, in get_requires_for_build_wheel
return self._call_hook('get_requires_for_build_wheel', {
~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
'config_settings': config_settings
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
})
^^
File "E:\00\venv\Lib\site-packages\pip\_vendor\pyproject_hooks\_impl.py", line 321, in _call_hook
raise BackendUnavailable(data.get('traceback', ''))
pip._vendor.pyproject_hooks._impl.BackendUnavailable: Traceback (most recent call last):
File "E:\00\venv\Lib\site-packages\pip\_vendor\pyproject_hooks\_in_process\_in_process.py", line 77, in _build_backend
obj = import_module(mod_path)
File "D:\Program Files\Lib\importlib\__init__.py", line 88, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
File "<frozen importlib._bootstrap>", line 1310, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 1026, in exec_module
File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
File "E:\TEMP\pip-build-env-kbzfw4bd\overlay\Lib\site-packages\setuptools\__init__.py", line 10, in <module>
import distutils.core
ModuleNotFoundError: No module named 'distutils'
Launch unsuccessful. Exiting.
Для продолжения нажмите любую клавишу . . .
Цитата: Злоп от 28 марта 2025, 00:32насколько я понимаю - установка неуспешно
ModuleNotFoundError: No module named 'distutils'
Launch unsuccessful. Exiting.
Для продолжения нажмите любую клавишу . . .
Спасибо.
Прошу меня простить.
Сегодня постараюсь поправить - добавил новый модуль, и забыл его в requirements.txt включить.
Цитата: Злоп от 28 марта 2025, 00:14Что с многопользовательской работой? что с блокировками/транзакциями?
Обычная "web-морда" с асинхронным поведением.
Поэтому многопользовательская работа в принципе нормальная.
Транзакции - на каждое изменение, плюс логирование всех изменений - как часть платформы.
Блокировки делать не стал :(. У меня на них многолетняя трудовая аллергия.
Выкрутился через очередь транзакций и маниакальное логирование каждого реквизита.
Смысл такой: При одновременной работе с одним и тем же объектом каждое изменение сохраняется в истории с временем и пользователем. Если два пользователя решили поменять наименование в справочнике - то оба их варианта сохранятся. "Правильность" определяется - кто последний - тот и "виновник". И каждое из изменений с помощью "ползунка таймлайна" - можно сделать актуальным.
А кто из- них прав в итоге - пусть пользователи выясняют друг с другом.
(Знаю что это неприятно (и как 1с-ник понимаю что "истина где-то рядом") - но система то, тут причем? Не знаю как вы - но если я получу сообщение - что "объект заблокирован" - меня это больше растраивает, чем гипотетическая правда о том что система "так защищает ваши данные". Имхо - Все данные - важны. Потеря данных при попытке их записать - это гораздо хуже. Опять же имхо. Не нарываюсь на холивар...)
Я могу наложить транзакцию, + включить блокировку, выполнить кучу действий с кучей объектов, зафиксировать транзакцию и только потом выключить блокировку. У меня есть варианты когда я даже не должен допускать грязное чтение кучи объектов...
?
Пока только на лицо хочу посмотреть как это выглядит.
Никике джавы учить не хочу.
Никаких джав - чесслово.
Скинул в личку ссылку на демку.
Цитата: Злоп от 28 марта 2025, 15:22Я могу наложить транзакцию, + включить блокировку, выполнить кучу действий с кучей объектов, зафиксировать транзакцию и только потом выключить блокировку. У меня есть варианты когда я даже не должен допускать грязное чтение кучи объектов...
?
У меня таких вариантов тоже есть "море". Но, пока обхожусь (обтекаю)... Спорить не буду. Блокировки бывают например нужны для исключения конкуренции за объект. Но и прямо сильной надобности не вижу.
Вот где прямо реально может пригодится - это вопросы (политики) безопасности (на чтение, на запись и т.д.). Но я до них в проекте еще не добрался... Двигаюсь от функциональности - к безопасности.
Почему только Злопу?
Я тоже глянуть хочу.
Йех.
(с закрытыми глазами давлю на кнопки)
База на сервере в теории - должна пересоздаваться раз в день. И это не факт.
Сервер тут: fortea2.ru
Админский доступ - дает доступ к конфигуратору и ко всему - что админ может делать (включая создание юзеров - через админку Django).
odmen
qweqwe123123
Юзер - ограничен в области видимости - может создавать только документы (в проекте - называются Контракты).
just_user
poiPOI098
Продвинутый юзер - может редактировать справочники и контракты.
power_user
sadhfjwei
Прошу ничего сильно не ломать.
А так - велкам.
Цитата: 1ex от 28 марта 2025, 15:41Блокировки бывают например нужны для исключения конкуренции за объект.
ПроцессN:
Стартанули. Точка А
прочитали кучу данных из кучи разных таблиц.
сделали кучу вычислений.
записали кучу данных в кучу разных таблиц
Финиш. Точка Б.
.
надо чтобы пока не отработает процесс1 от А до Б - чтобы аналогичный процесс2 (который будет использовать те же самые объекты от А до Б) ждал (или получил отлуп).
.
Реализуемо?
.
в клюшках просто выставлял логическую блокировку (если она еще не была выставлена, а если уже стояла - то ждал/отлуп), делал что надо, снимал блокировку.
Цитата: 1ex от 28 марта 2025, 15:33Никаких джав - чесслово.
Скинул в личку ссылку на демку.
Посмотрел бегло.
Жуть.
Фейс ни в дугу.
Как сырец-демо что в принципе что-то можно сделать - может быть... в принципе...
Фейс растянутый адски, похож на перспективный фейс 8-ки, от которого все шарахаются ;-)
Но я злоп, с годами стал требователен к красоте мира, поэтому мое мнение так себе...
Цитата: Злоп от 28 марта 2025, 23:47Цитата: 1ex от 28 марта 2025, 15:41Блокировки бывают например нужны для исключения конкуренции за объект.
ПроцессN:
Стартанули. Точка А
прочитали кучу данных из кучи разных таблиц.
сделали кучу вычислений.
записали кучу данных в кучу разных таблиц
Финиш. Точка Б.
.
надо чтобы пока не отработает процесс1 от А до Б - чтобы аналогичный процесс2 (который будет использовать те же самые объекты от А до Б) ждал (или получил отлуп).
.
Реализуемо?
.
в клюшках просто выставлял логическую блокировку (если она еще не была выставлена, а если уже стояла - то ждал/отлуп), делал что надо, снимал блокировку.
Сделал такое через "каскадные таски". Смысл в создании вложенных "умных" транзакций. Все как вы и описали. Умных - имею в виду, что это иерархия полноценных задача, с кодом условий (в основном шаблонированах - чтобы не писать код условий типа: Если таск такой-то - завершился, то стартуем другой.)
Я для разработки написал документик по Таскам. Вот - делюсь, можно кидать тапками: https://disk.yandex.ru/i/uakeZ9H7x6HnVw
Может не все еще работает - но таков путь :)
Цитата: Злоп от 28 марта 2025, 23:49Посмотрел бегло.
Жуть.
Фейс ни в дугу.
Как сырец-демо что в принципе что-то можно сделать - может быть... в принципе...
Фейс растянутый адски, похож на перспективный фейс 8-ки, от которого все шарахаются ;-)
Но я злоп, с годами стал требователен к красоте мира, поэтому мое мнение так себе...
Спасибо, что вообще посмотрели :)
(Ща, сочиню слезливую историю о том, почему мы такие убогие :) )
Начало анекдота...
Собрались как-то математик, 1с-овец (я), и бакендер (Фил).
Я, вместе с математиком, написал
Суперсложную Фигню стройную теорию. которую положил на хабр.
Если не получится осилить сотни две (три), формул - не ходите сюда:
https://habr.com/ru/articles/755158/
Бакендер сказал - какая
Суперсложная Фигня стройная теория, ща запилим.
Выкатил в итоге ядро, и спросил: -
А фронт вообще нужен? Я
почесал в затылке долго думал, и сказал: Давай сделаем шаблон из нескольких HTML страниц с каким-нибудь базовым CSS. Если вообще кому-нибудь кроме нас
Эта СФ этот хороший проект понадобится - то из-за открытых исходников могут подправить шаблоны страниц так, чтобы не вызывать резь в глазах. А нам "внутри" и так хватит. Я к сожалению для остальных - предпочитаю функциональность - красоте.
Зачем я это все: Фронтендера у меня пока нету - и когда появится - непонятно.
А в разработке у меня принцип: Устойчивость - Функциональность - Безопасность - Красивости и плюшки. Так-что доберусь когда-нибудь.
На гитхабе поправил проект (база - с простенькой демкой).
Старую версию - удалить.
Качаем, распаковываем, ничего вроде править не надо.
start.bat
ждем (надеюсь) вот такого :)
"Starting development server at http://127.0.0.1:8000/"
admin/admin
Не робит.
Считаю что это надо сначала проверять на "чистой" системе, т.е. ну... на эталлоной, поставленной с нуля, а потому уже выкладывать.
И т.п, и т.д. но я бы не сказал что у нас всех "лапки", мы это могём все поправить, но это довольно затруднительно по времени.
Возможно наши системы (разработчиков для 7.7/и восьмой хрени) настолько загажены всяким необходимым, что так это не взлетает.
Образ системы помог бы проще это оценить.
З.Ы. Это не претензия, это пожелание.
Я всегда говорю спасибо...
Так что - Спасибо. :)
Если время будет - можно (пожалуйста) попросить лог запуска ( можно и в личку)?
Так, то да :( . Даже у себя локально - запускал на десятке машин. На трех не поднялось совсем. Ощущение было, что борьба с зависимостями ведет на темную сторону Linux...
Винда разная, дрова разные, особенно если у кого mySql стоял. у 1С-ников кстати хуже всего стартануло.
В разработке две ветки. Одна - настольная, под винду (там пакет для шедулера другой), могу собрать виндовый образ под VMware Player, образ будет - чище некуда. Постараюсь на майских запилить. Ссылку положу.
Второй - под linux. Там шедулер - на Кроне. Там могу (правда "лапки" тут присутствуют :( ) в теории собрать docker образ, если кому надо (но быстро не обещаю)...
(venv) r:\forTea-main>start.bat
python
r:\forTea-main\venv
""
venv "r:\forTea-main\venv\Scripts\Python.exe"
Traceback (most recent call last):
File "r:\forTea-main\manage.py", line 11, in main
from django.core.management import execute_from_command_line
ModuleNotFoundError: No module named 'django'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "r:\forTea-main\manage.py", line 22, in <module>
main()
~~~~^^
File "r:\forTea-main\manage.py", line 13, in main
raise ImportError(
...<3 lines>...
) from exc
ImportError: Couldn't import Django. Are you sure it's installed and available on your PYTHONPATH environment variable? Did you forget to activate a virtual environment?
Для продолжения нажмите любую клавишу . . .
Джанго то стоит, пип его ставил, дальше копаться не стал.
Докер так себе, не охота изучать, один раз поставил так вся система начала дико тормозить, снес - стало как и раньше.
На этом знакомство с докером и закончилось ;)
Простенькая виртуалочка бы не помешала, лучше наверное на linux, если без всяких офисов с минимальным гуи типо xfce или lxde (xubuntu/lubuntu) то и размер будет приемлимый и лицензионность соблюдена.
Почему именно на основе ubuntu? Да потому что мануалей по ней на порядок больше, чем по остальным вариантам, это упрощает решение странных ситуаций.
Да, кстати, база sqlite очень грамотно спроектирована, явных косяков не вижу.
Небольшие все таки есть, ну например "value" text NULL CHECK((JSON_VALID ("value") OR "value" IS NULL))
Это много где используется.
Подозреваю что OR "value" IS NULL было добавлено позже первоначального проектирования.
Я бы поменял местами проверки, т.к. оптимизатор в sqlite достаточно дуболомный, чтобы понять что надо переставить проверки местами, а если учесть что JSON_VALID занимает больше времени чем проверка на NULL (что вообще ничего почти не занимает), то это может серьезно поднять скорость работы базы.
А! Вдогонку, sqlite же jsonb держит, перевод на него тоже может несколько ускорить работу. Или там уже jsonb уже используется?
По Linux - принял, сделаю.
По базе...
Эм...
чтобы не соврать - скажу, что sqlite родился из-за порта с mariaDB (та самая родительская ветка с Linux версии и с отдельным DB сервером).
Причем порт был в "лоб" с минимальными поправками для совместимости (чтобы хоть работало :)).
Понадобился он для локальных разработок (ну там - архив документов с распознаванием поднять на коленке, концепты потестить - в отрыве от серверной), поэтому вот такие "неоптимальности" и есть.
Оптимизации, у меня, обычно в конце списка... НО! :) про эти неоптимальности - я даже и не подумал.
Спасибо.
Добавил в список косяков :).
Я то пишу так:
"
# Справочники
class Designer(models.Model):
name = models.CharField(max_length=100)
formula = models.CharField(max_length=100, null=True)
delay_settings = models.JSONField(default={'handler': None, 'auto_approve': False})
parent = models.ForeignKey('self', on_delete=models.DO_NOTHING, null=True)
is_required = models.BooleanField(null=False, default=False)
default = models.CharField(max_length=500, null=True)
is_visible = models.BooleanField(default=False)
priority = models.IntegerField(default=0)
value = models.JSONField(null=True)
delay = models.BooleanField(null=True)
system = models.BooleanField(default=False)
settings = models.JSONField(null=True)
"
А ORM Django превращает json - в тот самый
"JSONField": "text"
, который в свою очередь превращает его (в элегантные шорты) в
data_type_check_constraints = {
....
JSONField": '(JSON_VALID("%(column)s") OR "%(column)s" IS NULL)',
Вот и получаю лажу неоптимальные хреновины решения.
Это были предположения, на продакшене возможно что я был не прав.
Проверка на null возможно лишняя, но это опять требует проверки, возможно это проверяется раньше.и эта проверка лишняя.
10 уже лет уже сижу на sqlite (всякие адаптеры ко всякой хрени), для 7.7 это очень сильный буст дла базы
Если будут проблемы с запросами - звони/стучи, не проблема их посмотреть.
Так...
https://cloud.mail.ru/public/ywyM/xztK7PYoi
Качается как архив (3.7 гига)
Образ для VMware (у меня сейчас такой - Workstation 17 Pro)
Небольшой ман и пара замечаний:
Гостевая система в VMWare: fortea-xubuntu
Пользователь в системе (логин/пароль): fortea/42
Для запуска веб-приложения нужно открыть терминал, зайти в папку fortea
"cd /home/fortea/fortea/"
и запустить runserver следующей командой:
python3 manage.py runserver 127.0.0.1:8000
В файле settings.py сейчас есть две конфигурации. По умолчанию включена конфигурация "Тренер". Также есть вторая конфигурация - пустая БД.
Пользователи:
У "Тренера" два пользователя:
Администратор (логин/пароль): odmen/admin123!
Юзер (логин/пароль): ylka/ylka
У пустой БД один пользователь с правами администратора: admin/admin
Включен системный крон (crontab), который необходим для работы выполнения отложенных значений (delay). По умолчанию он работает в режиме разработчика - будние дни 9-18:00. Настройте его по своему графику, если будете использовать delay, либо отключите, если не будете его использовать. Отредактируйте следующую строку в кронтабе:
* * 9-18 * 1-5 python3 ~/fortea/manage.py update_delays
Замечание 1:
Если нужно запустить образ в качестве сервера, а не "играться" внутри виртуалки, то запуск будет такой.
1. Смотрим сетевой адрес виртуалки.
2. И запускаем сервер командой типа "python3 manage.py runserver 192.168.х.х:8000"
Замечание 2:
Если вы работаете за проксей.
То скорее всего сходу не заведется :). Зайти - может и зайдет, но покажет большой кусок пиццы. Это значит, что "стили" (бутстрапы всякие) не загрузились. Тогда настраивайте прокси
в /etc/environment добавляете строчки
http_proxy="https://user:pass@proxy.host.com:8081"
https_proxy="https://user:pass@proxy.host.com:8081"
и перезагрузка.
А на хост машине (на винде) - за той же проксей, ставите ip виртуалки в "не использовать прокси-сервер".
Тогда должно заработать...
Может кучу очевидностей написал, но лучше перебдеть :).