UI integration package
Project description
Quickstart guide
Инициализация
> pip install 2m
Переходим в рабочий каталог своего приложения:
> cd ../path_to_your_ui
Устанавливаем зависимые пакеты, сверяем соответствие, развёртываем пакет с модулями:
> python -c "from two_m_root.install import install;exec(install.main())"
Теперь в вашем текущем покете появился пакет two_m, содержащий несколько модулей, которые необходимо настроить.
Настройка
- Опишем свои таблицы в models.py
Обращаю ваше внимание на официальную документацию Flask-SQLAlchemy https://flask-sqlalchemy.readthedocs.io/en/stable/legacy-quickstart/#define-models
- procedures.py
Если нужно работать с хранимыми процедурами, декларируем их в виде экземпляров класса DDL.
Документация SqlAlchemy относительно объектов DDL https://docs.sqlalchemy.org/en/20/core/ddl.html#custom-ddl
- Настроим .env файл, содержащий константы, которые конфигурируют работу базы данных и локального хранилища
После написания таблиц в models и хранимых процедур в procedures, нужно инициализировать их в базу даных.
> python -c "from two_m.models import create_db;create_db()"
> python -c "from two_m.procedures import init_procedures;init_procedures()"
- Наконец, можно приступить к использованию! Импортируем класс Tool и начнём работу!
from two_m_root.core import Tool
from two_m.models import SomeModel
...
...
...
class Something:
def __init__():
self.tool = Tool()
self.tool.set_model(SomeModel)
def ui_action_a():
self.tool.set_item(...)
def ui_action_b():
self.tool.set_item(...)
def ui_action_b():
items = self.tool.get_items(...)
...
Рассмотрим функционал, который является основной компетенций данного фреймворка
-
orm.set_item(_model=None, _ready=False, _insert=False, _update=False, _delete=False, _where=None, **values)
Установить в очередь запись-кандидата, которая появится в базе данных при первой возможности
-
- _model: Таблица из модуля models.py. Можно не указывать, если в текущем контексте (вашего приложения) уже установлена таблица в качестве основной (смотри класс ORM, метод set_model)
-
- _ready: Логическое значение. До тех пор, пока это значение False, нода будет находиться в очереди, но commit базы данных не попадёт. Идеальный способ передавать ответ от вашего валидатора
-
- _insert, _update, _delete: Логическое значение. DML-SQL
-
- _where: Словарь вида column_name:value для выражения where
-
- return None
Пример: пользовательская функция-валидатор даёт ответ, готова ли данная запись на транзакцию во "внешний мир":
-
orm.get_items(_model=None, _db_only=False, _queue_only=False, **where) -
- _model: Таблица из модуля models.py. Можно не указывать, если в текущем контексте (вашего приложения) уже установлена таблица в качестве основной (смотри класс ORM, метод set_model)
-
- _db_only: Получать данные только из базы данных, игнорируя локальные элементы
-
- _queue_only: Получать данные только из локальной очереди элементов, игнорируя базу данных
-
- return Result
-
orm.join_select(*models, _db_only=False, _queue_only=False, _on=None, **where) -
- models: Таблицы из модуля models.py между которыми существует отношение (PK-FK)
-
- _db_only: Получать данные только из базы данных, игнорируя локальные элементы
-
- _queue_only: Получать данные только из локальной очереди элементов, игнорируя базу данных
-
- _on: Словарь. Выражение ON в JOIN запросах. modelName.column1: modelName2.column2
-
- return JoinSelectResult
Несколько слов о принципе работы внутренних механизмов, которые объединяют воедино записи из удалённого расположения (базы данных), и записи из локального хранилища. Рассмотрим 1 строку из таблицы А и 1 строку из таблицы B, чтобы понять, как будет происходить слияние.
- Обе записи в отношениях (PRIMARY_KEY - FOREIGN KEY) находятся в локальном расположении
- Запись из базы данных (PRIMARY_KEY), а запись, которая на неё ссылается (FOREIGN KEY) находится в локальном хранилище
- Нетипичный случай, когда пользователь установил в столбец (FOREIGN KEY) значение,
первичный ключ от этого не нашёлся ни среди элементов из базы данных, ни в локальных.
В этом случае будут получены обе записи в отношениях (PRIMARY_KEY - FOREIGN KEY) из базы данных, если таковые имеются;
В противном случае этой записи не будет в результатах
BaseResult
Union[Result, JoinSelectResult]
Он жеОбъект результата
Объекты результата, производные от класса BaseResult, возвращаемые методами orm.get_items и orm.join_select соответственно, являются ЛЕНИВЫМИ объектами, то есть не содержат никакого результата явным образом, но хранят в себе все детали запроса. При каждом взаимодействии с итератором, contains, getitem, bool, len и даже str, происходит новый запрос.
: - Что это, зачем, - зачем усложнять? Ведь можно написать запрос и получить ответ: здесь и сейчас :question:
Во-первых, я нахожу весьма удобным не писать отдельных пользовательских функций для мемоизации параметров запроса,
чтобы потом возвращаться к этому снова и снова, заполняя своё приложение потенциально лишним кодом.
Во-вторых, "под капотом" скрывается достаточно хитрая система, которая, если описать это просто, делает следующее:
- Извлекает записи из базы данных
- Извлекает записи из локальной базы данных
- Реплицирует одно на другое: на записи из базы данных накладываются записи, которые хранятся локально, и, по тем или иным причинам, пока ещё не закоммитились.
В-третьих, эти ленивые экземпляры дают большое количество синтаксического сахара, который, по заветам pythonicway,
избавит ваш интерфейс от каждой лишней строчки!
- has_changes(hash_value=None) -> Optional[bool]
Просто обратимся к экземпляру, чтобы узнать, есть ли изменения в данных:
Если значение хеш-суммы никогда не фигурировало в рамках текущего экземпляра результата, вернёт - None.
- has_new_entries
Также, можно с лёгкостью узнать, появились ли новые (или стали недоступны те, что получены) записи:
Result
Объект запроса к 1 таблице.
- items - property - ResultORMCollection
- iter - ResultORMCollection._ iter _()
- visible_items - property - ResultORMCollection. Только ноды с атрибутом 'ui_hidden': False в словаре value.
- bool - True, если есть хотя бы 1 результат, иначе False
- len - От количества ResultORMItem в ResultORMCollection
- getitem - Вернёт новый экземпляр ResultORMCollection с одним или несколькими ResultORMItem по:
- Индексу (порядковый номер в коллекции, начиная с 0)
- Хеш-сумме пары ключ-значение у ResultORMItem. См свойство hash_by_pk
- Полной хеш сумме ResultORMItem
- Названию таблицы
- contains - Поддерживается возможность проверки содержания следующих типов:
- ResultORMItem
- Индекс в коллекции - int
- Название таблицы - str
- Хеш-сумма от ResultORMItem - int
- Хеш-сумма первичного ключа+значения. Можно получить через ResultORMItem.hash_by_pk - int
- hash - Получить полную хеш-сумму всех значений в словаре значений каждого экземпляра ResultORMItem, в рамках текущего экземпляра контейнера - ResultORMCollection
- pointer - (property) геттер и сеттер для инициализации Pointer
JoinSelectResult
Объект запроса к нескольким таблицам. В рамках результирующего списка каждый ResultORMCollection представляет внутри себя связку PK-FK.
- items - property - tuple(ResultORMCollection)
- iter - tuple(ResultORMCollection)._ _ iter_ _()
- visible_items - property - кортеж ResultORMCollection. Если в одной из нод, в рамках одной группы нод, имеют 'ui_hidden': True в словаре value, то данная группа будет скрыта из результатов.
- bool - True, если в списке есть хотя бы 1 результат ResultORMCollection, иначе False
- len - От количества ResultORMCollection в кортеже результатов
- getitem - Вернёт новый экземпляр ResultORMCollection по одному из следующих способов:
- Индекс в результирующем кортеже - int
- Хеш-сумма hash(sum(map(...ResultORMCollection)))
- Хеш-сумма первичных ключей+значений внутри ResultORMCollection - int
- contains - Поддерживается возможность проверки содержания следующих типов:
- ResultORMCollection
- ResultORMItem
- hash_sum - int
- Хеш-сумма первичных ключей+значений из всех элементов внутри ResultORMCollection. Можно получить через ResultORMCollection.hash_by_pk - свойство(property) - int
- hash - сумма всех ResultORMCollection._ hash _() в результирующем списке
- pointer - (property) геттер и сеттер для инициализации Pointer
Pointer
Ассоциируйте строку, представляющую данные, со ссылкой на получение этих данных. Работает как для запросов к 1 таблице, так и для запросов к нескольким таблицам одновременно.
Экземпляр Pointer инкапсулируется в экземпляр результата и предназначен для чтения только по свойству, - не следует пытаться сделать на него ещё одну ссылку :rage:
Инициализация
any_result.pointer = ["список", "совпадающий", "по", "длине", "с", "содержимым"]
Каждый элемент этого списка будет ассоциирован с содержимым внутри результата 1 к 1.
Использование
- getitem
any_result.pointer["содержимым"]- получить [-1] элемент
any_result.pointer["список"]- получить [0] элемент
any_result.pointer["совпадающий"]- получить [1] элемент
И так далее... - contains
"длине" in any_result.pointer # True
"strstr" in any_result.pointer # False
"с" in any_result.pointer # True
"совпадающий" in any_result.pointer # True
any_result.pointer.has_changes(name: str)-> Optional[bool] - Передаём сюда полную хеш сумму и получаем ответ на вопрос: есть ли какие-нибудь изменения (с момента последнего вопрошания или инициализации).
Если переданного значения не было в списке при инициализации, вернёт None.
any_result.pointer.is_valid() -> bool. Узнать о текущем состоянии текущего экземпляра Pointer: закрылся он или нет.
any_result.pointer.wrap_items-> list. Исходный список строк. Если данный Pointer закрыт, список будет пустым.any_result.pointer.items-> Полный словарь содержимого в виде:{"одна_из_строк_wrap": контейнер_с_содержимым}any_result.pointer.replace_wrap(item: str, old_wrapper: Optional[str] = None, hash_: Optional[int] = None, primary_key_hash: Optional[int] = None, index: Optional[int] = None)-> None. Заменить строку указатель на новую.-
- item: Новая строка
-
- old_wrapper: Старая строка из wrap_items
-
- hash_: Полная хеш сумма результата, у которой следует заменить строку-указатель
-
- primary_key_hash: Хеш-сумма первичного ключа и значения результата, у которого следует заменить строку-указатель
-
- index: Индекс записи в результате, у которой следует заменить строку-указатель
Инвалидация
И всё было бы хорошо, но как только из базы данных придёт результат количественно другой, или, с записями, которые содержат другие первичные ключи; Если то же самое произойдет и со стороны локальных элементов,- объект сразу же откажется сотрудничать с вами. Всеми своими методами он будет отвечать - None. Всё что можно сделать в этой ситуации - создать новый :)
Содержимое результата
Union[ResultORMCollection, ResultORMItem]
Контейнер ResultORMCollection
Контейнеры с данными, возвращаемый объектом результата - Result или JoinSelectResult. Иммутабелен.
- ResultORMCollection - композиция из ResultORMItem.
В коллекции нод результата предусмотрена возможность установить/удалить префикс с названием таблицы в каждый столбец. Это может оказаться полезным при разработке UI.
-
- prefix - свойство(property). Возвращает литерал, указывающий на текущую конфигурацию относительно префиксов: "auto", "add", "no-prefix"
-
- add_model_name_prefix - Метод(callable). Установить всем столбцам значений, находящихся в каждом ResultORMItem, префикс с названием таблицы
-
- remove_model_name_prefix - Метод(callable). Удалить префикс с названием таблицы из каждого значения каждого ResultORMItem
-
- auto_model_name_prefix - Метод(callable). Если какой-либо столбец(его название) повторяется в каком-либо ResultORMItem текущего контейнера, то добавить префикс, иначе не добавлять
-
- all_nodes - Итератор со всеми ResultORMItem. Он возвращает все ноды, включая те, которые находятся в очереди и должны сделать delete в базе данных.
Призываю не использовать метод all_nodes, он нужен для служебного пользования :rage:
-
- get_node(model, primary_key, value) - Получить ResultORMItem или Exception
-
- search_nodes(model, **столбцы_и_значения) - Получить коллекцию ResultORMItem или пустую коллекцию
-
- hash - Получить полную хеш-сумму всех значений в словаре значений каждого экземпляра ResultORMItem, в рамках текущего экземпляра контейнера - ResultORMCollection
-
- hash_by_pk - свойство(property). Получить хеш-сумму всех первичных ключей и их значений у всех ResultORMItem, в рамках текущего экземпляра контейнера - ResultORMCollection
-
- iter - Итератор со всеми ResultORMItem исключая те, под которыми скрываются пустые - которые должны удалить запись из базы данных
-
- bool - На основе количества элементов из iter
-
- getitem - Вернёт новый экземпляр ResultORMCollection с одним или несколькими ResultORMItem по:
- Индексу (порядковый номер в коллекции, начиная с 0)
- Хеш-сумме пары ключ-значение у ResultORMItem. См свойство hash_by_pk
- Полной хеш сумме ResultORMItem
- Названию таблицы
-
- contains - Поддерживается возможность проверки содержания следующих типов:
- ResultORMItem
- Индекс в коллекции - int
- Название таблицы - str
- Хеш-сумма от ResultORMItem - int
- Хеш-сумма первичного ключа+значения. Можно получить через ResultORMItem.hash_by_pk - int
Единица результата ResultORMItem
-
- value - свойство(property) - Словарь с содержимым в виде
{столбец: значение}
- value - свойство(property) - Словарь с содержимым в виде
-
- hidden - свойство(property) - Скрыт ли элемент из набора результатов
-
- model - свойство(property) - Таблица текущего элемента
-
- hash_by_pk - свойство(property). Хеш-сумма первичного ключа и значения
-
- get(def_value=None) - Тот же getitem, но с возможностью получить значение по умолчанию
-
- get_primary_key_and_value(only_key=False, only_val=False) - Словарь. Пара
{столбец: значение}. Или что-то одно
- get_primary_key_and_value(only_key=False, only_val=False) - Словарь. Пара
-
- add_model_name_prefix - Метод(callable). Добавить каждому ключу в словаре value префикс с названием таблицы
-
- remove_model_name_prefix - Метод(callable). Удалить префиксы
-
- hash - Получить полную хеш-сумму всех значений в словаре значений
-
- contains - 2 варианта использования:
- строка вида
имя_столбца:значение - просто имя столбца
-
- getitem - Получить значение столбца по его наименованию
value = node["table_column"]
- getitem - Получить значение столбца по его наименованию
-
- bool - От длины словаря value
Тестовый проект
Пример конфигурации с моделями, хранимыми процедурами(триггерами) и тестами!
Postgresql в качестве базы данных
Changelog
1.1
-
Pointer
Добавлен метод replace_wrap. wrap_items теперь список, а не кортеж. Более мягкое поведение относительно возбуждения WrapperLengthException, если данных нет. pymemcache.RetryingClient вместо pymemcache.Client в свойстве Tool.cache.
Отказ от идеи наследования класса Tool в пользовательский пакет two_m, модуль main. Напротив, из two_m.main теперь импортируются константы в two_m_root.core.
1.2
Result.order_by(...), JoinSelectResult.order_by(...)
-
Result и JoinSelectResult получили метод order_by от миксина OrderByMixin Сортировка возможна по длине строк, времени добавления, или в алфавитном порядке. По любому столбцу в таблице или просто по первичному ключу.
Пример использования:
- Инициализируем объект Result или JoinSelectResult с интересующими нас параметрами.
lazy_result = my_tool_instance.get_items(table_name, ...)- Вызываем метод order_by, передавая один или несколько параметров.
lazy_result.order_by(...)- Теперь, каждый раз, когда вы выполняете итерации по обновлямому результату, будет происходить сортировка.
Экземплярам класса Result и JoinSelectResult добавлены методы:
- visible_items (property) - Получить экземпляр ResultORMCollection, содержащем ноды с _delete=True в значениях (они должны удалить запись)
- hidden_items (property) - Получить экземпляр ResultORMCollection содержащий только скрытые ноды
BaseResult получил константу ITER_ONLY_VISIBLE_ITEMS_AS_DEFAULT, определяющую поведение относительно скрытых нод. Обратим внимание, что это, в свою очередь, затрагивает работу Pointer.
-
ConnectionManager
Все соединения с внешними сервисами вынесены в отдельный класс. Открытые подключения закрываются по таймерам, не засоряя пул. Можно настроить срок жизни подключения.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file 2m-1.2.5-py3-none-any.whl.
File metadata
- Download URL: 2m-1.2.5-py3-none-any.whl
- Upload date:
- Size: 71.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
18abc0bafa3cd96c4d781ff4bbda9fef623e4c37a834944665bd79708641a903
|
|
| MD5 |
d29a1419b2c15fcdcddbb5452184d3d2
|
|
| BLAKE2b-256 |
2d2faf560fd074cfd80c3e5cae0be4d0241e1e3b166fda0de8e9392fe27b4ef9
|