Список заказов

Пользовательский список, который управляет информацией об индексе/позиции содержащихся в нем элементов.

автор:

Джейсон Киртланд

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])

Подготавливает фабрику OrderingList для использования в определениях отображения.

OrderingList

Пользовательский список, который управляет информацией о позиции для своих дочерних элементов.

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

Синхронизировать упорядочивание для всей коллекции.

Просматривает список и убеждается, что для каждого объекта задана точная информация о заказе.

Вернуться на верх