Список заказов¶
Пользовательский список, который управляет информацией об индексе/позиции содержащихся в нем элементов.
- автор:
Джейсон Киртланд
orderinglist
- это помощник для мутабельных упорядоченных отношений. Он перехватывает операции со списком, выполняемые над управляемой коллекцией relationship()
, и автоматически синхронизирует изменения в позиции списка с целевым скалярным атрибутом.
Пример: Таблица slide
, в которой каждая строка ссылается на ноль или более записей в связанной таблице bullet
. Пули в слайде отображаются в порядке, основанном на значении столбца position
в таблице bullet
. По мере переупорядочивания записей в памяти значение атрибута position
должно обновляться, чтобы отразить новый порядок сортировки:
Base = declarative_base()
class Slide(Base):
__tablename__ = 'slide'
id = Column(Integer, primary_key=True)
name = Column(String)
bullets = relationship("Bullet", order_by="Bullet.position")
class Bullet(Base):
__tablename__ = 'bullet'
id = Column(Integer, primary_key=True)
slide_id = Column(Integer, ForeignKey('slide.id'))
position = Column(Integer)
text = Column(String)
Стандартное отображение отношений создает для каждого Slide
атрибут типа списка, содержащий все связанные с ним Bullet
объекты, однако автоматическая обработка изменений в упорядочивании не производится. При добавлении Bullet
в Slide.bullets
атрибут Bullet.position
будет оставаться неустановленным до тех пор, пока не будет назначен вручную. При вставке Bullet
в середину списка следующие объекты Bullet
также необходимо будет перенумеровать.
Объект OrderingList
автоматизирует эту задачу, управляя атрибутом position
у всех объектов Bullet
в коллекции. Он конструируется с помощью фабрики ordering_list()
:
from sqlalchemy.ext.orderinglist import ordering_list
Base = declarative_base()
class Slide(Base):
__tablename__ = 'slide'
id = Column(Integer, primary_key=True)
name = Column(String)
bullets = relationship("Bullet", order_by="Bullet.position",
collection_class=ordering_list('position'))
class Bullet(Base):
__tablename__ = 'bullet'
id = Column(Integer, primary_key=True)
slide_id = Column(Integer, ForeignKey('slide.id'))
position = Column(Integer)
text = Column(String)
С помощью приведенного выше отображения атрибут Bullet.position
управляется:
s = Slide()
s.bullets.append(Bullet())
s.bullets.append(Bullet())
s.bullets[1].position
>>> 1
s.bullets.insert(1, Bullet())
s.bullets[2].position
>>> 2
Конструкция OrderingList
работает только при изменениях в коллекции, а не при первоначальной загрузке из базы данных, и требует, чтобы список был отсортирован при загрузке. Поэтому обязательно укажите order_by
на relationship()
против целевого атрибута упорядочивания, чтобы упорядочивание было правильным при первой загрузке.
Предупреждение
OrderingList
обеспечивает ограниченную функциональность только в том случае, если целью сортировки является столбец первичного ключа или уникальный столбец. К неподдерживаемым или проблематичным операциям относятся:
две записи должны поменяться значениями. Это не поддерживается непосредственно в случае первичного ключа или уникального ограничения, поскольку в этом случае сначала придется временно удалить хотя бы одну строку или изменить значение на третье, нейтральное, пока происходит переключение.
запись должна быть удалена, чтобы освободить место для новой записи. Рабочий модуль SQLAlchemy выполняет все INSERT и DELETE в рамках одного флеша. В случае первичного ключа, чтобы уменьшить влияние этого ограничения, он поменяет INSERT/DELETE того же первичного ключа на UPDATE, однако для UNIQUE-столбцов этого не происходит. В будущем будет реализована возможность поведения «DELETE перед INSERT», что снимет данное ограничение, однако для этого потребуется явная настройка на уровне картографа для наборов столбцов, которые будут обрабатываться подобным образом.
ordering_list()
принимает в качестве аргумента имя атрибута упорядочивания связанного объекта. По умолчанию нулевой целочисленный индекс позиции объекта в ordering_list()
синхронизируется с атрибутом упорядочивания: индекс 0 получит позицию 0, индекс 1 - позицию 1 и т.д. Чтобы начать нумерацию с 1 или какого-либо другого целого числа, укажите count_from=1
.
Справочник по API¶
Object Name | Description |
---|---|
count_from_0(index, collection) |
Функция нумерации: последовательные целые числа, начинающиеся с 0. |
count_from_1(index, collection) |
Функция нумерации: последовательные целые числа, начиная с 1. |
count_from_n_factory(start) |
Функция нумерации: последовательные целые числа, начинающиеся с произвольного начала. |
ordering_list(attr[, count_from, ordering_func, reorder_on_append]) |
Подготавливает фабрику |
Пользовательский список, который управляет информацией о позиции для своих дочерних элементов. |
- function sqlalchemy.ext.orderinglist.ordering_list(attr: str, count_from: Optional[int] = None, ordering_func: Optional[Callable[[int, Sequence[_T]], int]] = None, reorder_on_append: bool = False) Callable[[], OrderingList] ¶
Подготавливает фабрику
OrderingList
для использования в определениях отображения.Возвращает объект, пригодный для использования в качестве аргумента опции
collection_class
отношения Mapper, например:from sqlalchemy.ext.orderinglist import ordering_list class Slide(Base): __tablename__ = 'slide' id = Column(Integer, primary_key=True) name = Column(String) bullets = relationship("Bullet", order_by="Bullet.position", collection_class=ordering_list('position'))
- Параметры:
attr – Имя сопоставленного атрибута, используемого для хранения и поиска информации о заказе
count_from – Задайте целочисленное упорядочивание, начиная с
count_from
. Например,ordering_list('pos', count_from=1)
создаст в SQL список, основанный на 1, сохраняя значение в столбце „pos“. Игнорируется, если задано значениеordering_func
.
Дополнительные аргументы передаются конструктору
OrderingList
.
- function sqlalchemy.ext.orderinglist.count_from_0(index, collection)¶
Функция нумерации: последовательные целые числа, начинающиеся с 0.
- function sqlalchemy.ext.orderinglist.count_from_1(index, collection)¶
Функция нумерации: последовательные целые числа, начиная с 1.
- function sqlalchemy.ext.orderinglist.count_from_n_factory(start)¶
Функция нумерации: последовательные целые числа, начинающиеся с произвольного начала.
- class sqlalchemy.ext.orderinglist.OrderingList¶
Пользовательский список, который управляет информацией о позиции для своих дочерних элементов.
Объект
OrderingList
обычно задается с помощью фабричной функцииordering_list()
, используемой совместно с функциейrelationship()
.Классическая подпись.
класс
sqlalchemy.ext.orderinglist.OrderingList
(builtins.list
,typing.Generic
)-
method
sqlalchemy.ext.orderinglist.OrderingList.
__init__(ordering_attr: Optional[str] = None, ordering_func: Optional[Callable[[int, Sequence[_T]], int]] = None, reorder_on_append: bool = False)¶ Пользовательский список, который управляет информацией о позиции для своих дочерних элементов.
OrderingList
- это реализация спискаcollection_class
, которая синхронизирует позицию в списке Python с атрибутом position на отображаемых объектах.Эта реализация полагается на то, что список начинается в правильном порядке, так что будьте уверены, что вы поставите
order_by
на свои отношения.- Параметры:
ordering_attr – Имя атрибута, хранящего порядок объекта в отношении.
ordering_func – Необязательно. Функция, сопоставляющая позицию в списке Python со значением для хранения в
ordering_attr
. Возвращаемые значения обычно являются (но не обязательно!) целыми числами. Функцияordering_func
вызывается с двумя позиционными параметрами: индексом элемента в списке и самим списком. Если этот параметр опущен, то для значений атрибутов используются индексы списка Python. В модуле предусмотрены две базовые функции нумерации:count_from_0
иcount_from_1
. Более экзотические примеры, такие как ступенчатая нумерация, алфавитная нумерация и нумерация Фибоначчи, приведены в модульных тестах.reorder_on_append – По умолчанию False. При добавлении объекта с существующим (не None) значением упорядочивания это значение будет оставлено нетронутым, если только значение
reorder_on_append
не равно true. Это оптимизация, позволяющая избежать различных опасных неожиданных записей в базу данных. SQLAlchemy будет добавлять экземпляры в список с помощью функции append() при загрузке объекта. Если по какой-то причине в наборе результатов из базы данных пропущен шаг в упорядочивании (например, строка „1“ отсутствует, а получены „2“, „3“ и „4“), reorder_on_append=True немедленно изменит нумерацию элементов на „1“, „2“, „3“. Если изменения вносятся в нескольких сессиях, любая из которых хотя бы мимоходом загружает эту коллекцию, то все сессии попытаются «почистить» нумерацию в своих коммитах, что может привести к ошибке одновременной модификации, кроме одной. Рекомендуем оставить значение по умолчанию False и вызыватьreorder()
только при выполнении операцийappend()
с ранее упорядоченными экземплярами или при выполнении уборки после ручных sql-операций.
-
method
sqlalchemy.ext.orderinglist.OrderingList.
append(entity)¶ Добавляет объект в конец списка.
-
method
sqlalchemy.ext.orderinglist.OrderingList.
insert(index, entity)¶ Вставить объект перед индексом.
-
method
sqlalchemy.ext.orderinglist.OrderingList.
pop(index=-1)¶ Удаление и возврат элемента по индексу (по умолчанию последний).
Вызывает ошибку IndexError, если список пуст или индекс выходит за пределы диапазона.
-
method
sqlalchemy.ext.orderinglist.OrderingList.
remove(entity)¶ Удалить первое вхождение значения.
Вызывает ошибку ValueError, если значение отсутствует.
-
method
sqlalchemy.ext.orderinglist.OrderingList.
reorder() None ¶ Синхронизировать упорядочивание для всей коллекции.
Просматривает список и убеждается, что для каждого объекта задана точная информация о заказе.
-
method