2.0 Changelog¶
2.0.16¶
Released: June 10, 2023platform¶
Улучшена совместимость, благодаря чему весь набор тестов работает на Python 3.12.0b1.
orm¶
Улучшена функция
DeferredReflection.prepare()
для приема произвольных аргументов**kw
, передаваемых вMetaData.reflect()
, что позволяет использовать такие случаи, как отражение представлений, а также передавать аргументы, специфичные для диалекта. Кроме того, модернизирован аргументDeferredReflection.prepare.bind
так, что в качестве аргумента «bind» принимается либоEngine
, либоConnection
.References: #9828
Исправлена проблема, когда декларативный базовый класс
DeclarativeBaseNoMeta
не работал с не отображенными миксинами или абстрактными классами, вызывая вместо этого ошибкуAttributeError
.References: #9862
В серии 2.0 исправлена регрессия, при которой значение по умолчанию
validates.include_backrefs
для функцииvalidates()
менялось наFalse
. Теперь это значение по умолчанию восстановлено доTrue
.References: #9820
Исправлена ошибка в новой функции, позволяющей использовать предложение WHERE в сочетании с ORM Bulk UPDATE по первичному ключу, добавленной в версии 2.0.11 как часть #9583, когда при отправке словарей, не содержащих значений первичных ключей для каждой строки, выполнялся массовый процесс, включающий «pk=NULL» для этих строк, что приводило к молчаливому отказу. Теперь при отсутствии значений первичных ключей для массового UPDATE выдается исключение.
References: #9917
Исправлена проблема, при которой не работала генерация полей dataclasses, задающих значение
default
и устанавливающих значениеinit=False
. Поведение dataclasses в этом случае заключается в установке значения по умолчанию для класса, что несовместимо с дескрипторами, используемыми SQLAlchemy. Для поддержки этого случая значение по умолчанию преобразуется вdefault_factory
при генерации класса данных.References: #9879
Предупреждение об устаревании выдается всякий раз, когда свойство добавляется в
Mapper
, где уже было настроено свойство, сопоставленное с ORM, или атрибут уже присутствует в классе. Ранее для этого случая существовало предупреждение, не связанное с депривацией, которое выдавалось непоследовательно. Логика работы этого предупреждения была улучшена таким образом, чтобы оно обнаруживало замену атрибута конечным пользователем и не давало ложных срабатываний для внутренних декларативных и других случаев, когда ожидается замена дескрипторов на новые.References: #9841
Улучшен отбор аргументов для параметра
map_imperatively.local_table
методаregistry.map_imperatively()
, обеспечивающий передачу толькоTable
или другогоFromClause
, а не существующего маппированного класса, что привело бы к неопределенному поведению при дальнейшей интерпретации объекта для нового маппинга.References: #9869
Атрибут
InstanceState.unloaded_expirable
является синонимом атрибутаInstanceState.unloaded
и в настоящее время устарел; этот атрибут всегда был специфичен для конкретной реализации и не должен был быть общедоступным.References: #9913
asyncio¶
В
create_async_engine()
добавлен новый параметрcreate_async_engine.async_creator
, который выполняет ту же задачу, что и параметрcreate_engine.creator
вcreate_engine()
. Это неаргументированный вызываемый параметр, который обеспечивает новое asyncio-соединение, используя непосредственно драйвер базы данных asyncio. Функцияcreate_async_engine()
обернет соединение на уровне драйвера в соответствующие структуры. Pull request curtesy of Jack Wotherspoon.References: #8215
postgresql¶
Приведение столбцов
NAME
кTEXT
при использованииARRAY_AGG
в отражении PostgreSQL. Это, по-видимому, улучшает совместимость с некоторыми производными PostgreSQL, которые могут не поддерживать агрегирование по типуNAME
.References: #9838
Унифицированные определения пользовательских операторов PostgreSQL, поскольку они являются общими для нескольких различных типов данных.
References: #9041
Добавлена поддержка в PostgreSQL 10
NULLS NOT DISTINCT
особенности уникальных индексов и уникальных ограничений с использованием опции диалектаpostgresql_nulls_not_distinct
. Обновлена логика отражения, которая также корректно учитывает эту опцию. Pull request любезно предоставлен Павлом Сиарченя.References: #8240
Использование правильного старшинства для специфических операторов PostgreSQL, таких как
@>
. Ранее предшествование было неверным, что приводило к неправильному выводу скобок при выводе на экран конструкцииANY
илиALL
.References: #9836
Исправлена проблема, когда параметры
ColumnOperators.like.escape
и подобные им не допускали в качестве аргумента пустую строку, которая передавалась как символ «escape»; такой синтаксис поддерживается PostgreSQL. Pull requset любезно предоставлен Мартином Каславски.References: #9907
2.0.15¶
Released: May 19, 2023orm¶
По мере того, как все больше проектов используют ORM-запросы нового стиля «2.0», становится очевидным, что условный характер «autoflush», основанный на том, ссылается ли данный оператор на ORM-сущности, становится все более ключевым поведением. До сих пор флаг «ORM» для утверждения был слабо связан с тем, возвращает ли утверждение строки, соответствующие ORM-сущностям или столбцам; первоначальное назначение флага «ORM» заключалось в том, чтобы включить правила выборки ORM-сущностей, которые применяют постобработку к наборам результатов Core, а также стратегии ORM-загрузчика к утверждению. Для операторов, не опирающихся на строки, содержащие ORM-сущности, флаг «ORM» был признан практически ненужным.
Может оказаться, что «autoflush» лучше использовать для всех случаев использования
Session.execute()
и связанных с ним методов, даже для чисто Core SQL-конструкций. Однако это все еще может повлиять на старые случаи, где этого не ожидается, и, возможно, это больше относится к версии 2.1. Однако на данный момент правила для «ORM-флага» были открыты таким образом, что оператор, включающий ORM-сущности или атрибуты в любом месте, в том числе в одном только предложении WHERE / ORDER BY / GROUP BY, в скалярных подзапросах и т.д., будет включать этот флаг. Это вызовет «автопромывку» для таких операторов, а также будет видно по атрибуту уровня событияORMExecuteState.is_orm_statement
.References: #9805
postgresql¶
Исправлен базовый тип данных
Uuid
для диалекта PostgreSQL, чтобы при выборе «native_uuid» полностью использовался специфичный для диалекта PG тип данныхUUID
, что позволяет учитывать поведение драйвера PG. Эта проблема стала очевидной в связи с улучшением insertmanyvalues, сделанным в рамках #9618, где, как и в #9739, драйвер asyncpg очень чувствителен к наличию или отсутствию приведения типов данных, и специфичный для драйвера PostgreSQL родной тип данныхUUID
должен быть вызван при использовании этого общего типа, чтобы эти приведения имели место.References: #9808
2.0.14¶
Released: May 18, 2023orm¶
Модифицирована реализация
JoinedLoader
для использования более простого подхода в одной конкретной области, где ранее использовалась кэшируемая структура, разделяемая между потоками. Это сделано для того, чтобы избежать потенциального состояния гонки, которое, как предполагается, является причиной конкретного сбоя, о котором неоднократно сообщалось. Кэшируемая структура по-прежнему в конечном итоге «кэшируется» через скомпилированный кэш SQL, поэтому снижения производительности не ожидается.References: #9777
Исправлена ошибка, при которой использование
update()
илиdelete()
внутри конструкцииCTE
, а затем в конструкцииselect()
приводило к возникновению ошибкиCompileError
, связанной с правилами выполнения операторов обновления/удаления на уровне ORM.References: #9767
Исправлена проблема в новой ORM Annotated Declarative, когда использование
ForeignKey
(или другого ограничения на уровне столбцов) внутриmapped_column()
, которое затем копируется в модели через pep-593Annotated
, приводило к применению дубликатов каждого ограничения кColumn
, созданного в целевомTable
, что приводило к некорректному DDL CREATE TABLE, а также к директивам миграции под Alembic.References: #9766
Исправлена проблема, когда при использовании дополнительных критериев отношений с опцией загрузчика
joinedload()
, когда сами дополнительные критерии содержали коррелирующие подзапросы, которые ссылались на объединенные сущности и, следовательно, также требовали «адаптации» к алиасным сущностям, эта адаптация исключалась, что приводило к неправильному предложению ON для объединенной загрузки.References: #9779
sql¶
Обобщение функции MSSQL
try_cast()
в пространство имен импортаsqlalchemy.
, чтобы она могла быть реализована и в сторонних диалектах. В SQLAlchemy функцияtry_cast()
остается конструкцией, предназначенной только для SQL Server, и при ее использовании с бэкендами, которые ее не поддерживают, будет возникать ошибкаCompileError
.try_cast()
реализует CAST, в котором некастируемые преобразования возвращаются как NULL, а не вызывают ошибку. Теоретически данная конструкция может быть реализована в сторонних диалектах для Google BigQuery, DuckDB, Snowflake и, возможно, других.Pull request любезно предоставлен Ником Крюсом.
References: #9752
Исправлена проблема в конструкции
values()
, при которой возникала внутренняя ошибка компиляции, если конструкция использовалась внутри скалярного подзапроса.References: #9772
postgresql¶
Исправлена очень старая проблема, когда параметр
ENUM.create_type
, установленный не по умолчаниюFalse
, не распространялся при копированииColumn
, частью которого он является, как это часто бывает при использовании декларативных микшинов ORM.References: #9773
tests¶
Исправлен тест, полагающийся на функцию
sys.getsizeof()
, который не выполнялся на pypy, где эта функция ведет себя иначе, чем на cpython.References: #9789
2.0.13¶
Released: May 10, 2023orm¶
Исправлена проблема, при которой ORM Annotated Declarative не во всех случаях корректно разрешала прямые ссылки; в частности, при использовании
from __future__ import annotations
в сочетании с Pydantic dataclasses.References: #9717
Исправлена проблема в новой функции Использование RETURNING в операторах upsert, когда опция выполнения
populate_existing
не распространялась на опцию загрузки, что не позволяло обновлять существующие атрибуты на месте.References: #9746
Исправлены проблемы с траекторией стратегии загрузчика, когда нетерпеливые загрузчики, такие как
joinedload()
/selectinload()
, не могли полностью пройти на много уровней вглубь после загрузки, имеющей в качестве промежуточного члена конструкциюwith_polymorphic()
или подобную ей.References: #9715
Исправлена проблема в конструкции
mapped_column()
, когда корректное предупреждение «столбец X назван непосредственно несколько раз» не выдавалось, когда ORM mapped атрибуты ссылались на один и тот жеColumn
, если была задействована конструкцияmapped_column()
, вместо этого выдавалось внутреннее утверждение.References: #9630
sql¶
Реализовано предупреждение о «картезианском произведении» для операторов UPDATE и DELETE, включающих несколько таблиц, не связанных между собой каким-либо образом.
References: #9721
Исправлен базовый класс для диалектно-специфических типов float/double; Oracle
BINARY_DOUBLE
теперь подклассыDouble
, а внутренние типыFloat
для asyncpg и pg8000 теперь корректно подклассыFloat
.Исправлена проблема, при которой конструкция
update()
, включающая несколько таблиц и не содержащая предложения VALUES, приводила к внутренней ошибке. Текущее поведение дляUpdate
без значений заключается в генерации SQL-оператора UPDATE с пустым предложением «set», поэтому для данного конкретного случая это было сделано единообразно.
schema¶
Улучшен способ добавления столбцов таблиц, что позволяет избежать лишних выделений и значительно ускорить создание многих таблиц, например, при отражении целых схем.
References: #9597
typing¶
Исправлена типизация параметра
Session.get.with_for_update
вSession.get()
иSession.refresh()
(а также соответствующих методов наAsyncSession
) для принятия булевыхTrue
и всех других форм аргументов, принимаемых параметром во время выполнения.References: #9762
Добавлен тип
ColumnExpressionArgument
в качестве публичного типа, указывающего на аргументы, ориентированные на столбцы, которые передаются в конструкции SQLAlchemy, такие какSelect.where()
,and_()
и другие. Это может быть использовано для добавления типизации в функции конечного пользователя, вызывающие эти методы.References: #9656
asyncio¶
Добавлен новый вспомогательный миксин
AsyncAttrs
, который призван улучшить использование lazy-loader и других ORM-атрибутов с истекшим сроком действия или отложенных атрибутов в asyncio, предоставляя простой атрибутный аксессор, обеспечивающийawait
интерфейс к любому ORM-атрибуту, независимо от того, нужно ли ему выдавать SQL.См.также
References: #9731
Исправлена проблема в полуприватных функциях параллелизма
await_only()
иawait_fallback()
, когда заданный ожидаемый оставался не ожидаемым, если функция выбрасывалаGreenletError
, что могло привести к появлению предупреждений «не ожидалось» в дальнейшем при продолжении работы программы. В данном случае ожидаемый объект отменяется до того, как будет выброшено исключение.
postgresql¶
Исправлена еще одна регрессия, связанная с изменением «insertmanyvalues» в версии 2.0.10 в составе #9618, аналогично регрессии #9701, где для работы с новым форматом bulk INSERT для типов данных
LargeBinary
также требуется дополнительное приведение при использовании драйвера asyncpg.References: #9739
oracle¶
В диалекте Oracle добавлена поддержка отражения в индексах, основанных на выражениях, и направления упорядочивания индексных выражений.
References: #9597
misc¶
2.0.12¶
Released: April 30, 2023orm¶
Исправлена критическая проблема кэширования, когда сочетание композиций выражений
aliased()
иhybrid_property()
приводило к несовпадению ключей кэша, в результате чего ключи кэша удерживали реальный объектaliased()
и не совпадали с ключами эквивалентных конструкций, заполняя кэш.This change is also backported to: 1.4.48
References: #9728
mysql¶
Исправлены проблемы с отражением комментариев к объектам
Table
иColumn
, когда комментарии содержали управляющие символы, такие как новые строки. В целом добавлена поддержка этих символов, а также расширенных символов Unicode в комментариях к таблицам и столбцам (последние не поддерживаются MySQL/MariaDB).References: #9722
2.0.11¶
Released: April 26, 2023orm¶
Функции ORM bulk INSERT and UPDATE теперь добавляют эти возможности:
Снято требование не передавать дополнительные параметры при использовании ORM INSERT с настройкой dml_strategy «orm».
Снято требование не передавать дополнительные критерии WHERE при использовании ORM UPDATE с настройкой dml_strategy «bulk». Обратите внимание, что в этом случае отключается проверка на ожидаемое количество строк.
Исправлена ошибка версии 2.0, когда использование
bindparam()
внутриInsert.values()
при выполнении оператораInsert
с помощью ORMSession
не интерпретировалось корректно из-за того, что новый ORM-enabled insert feature не реализовывал этот случай использования.
engine¶
Ряд улучшений производительности
Row
:Улучшена работа интерфейса «именованный кортеж» строки
__getattr__
; в рамках этого изменения оптимизирована реализацияRow
, удалены конструкции и логика, характерные для SQLAlchemy версии 1.4 и более ранних версий. В рамках этого изменения был немного изменен формат сериализацииRow
, однако строки, которые были замаринованы в предыдущих версиях SQLAlchemy 2.0, будут распознаваться в новом формате. Pull request любезно предоставлен J. Nick Koston.Улучшена производительность обработки строк для «бинарных» типов данных за счет того, что обработчик «bytes» стал условным для каждого драйвера. В результате обработчик результата «bytes» был удален практически для всех драйверов, кроме psycopg2, все из которых в современных формах поддерживают возврат «байтов» Python напрямую. Pull request любезно предоставлен J. Nick Koston.
Дополнительные рефакторинги внутри
Row
для повышения производительности от Федерико Казелли.
Исправлена регрессия, из-за которой не работал атрибут
URL.normalized_query
вURL
.References: #9682
sql¶
Добавлена поддержка доступа к фрагментам с
ColumnCollection
, например,table.c[0:5]
,subquery.c[:-1]
и т.д. Доступ к фрагменту возвращает подфрагментColumnCollection
точно так же, как и передача кортежа ключей. Это естественное продолжение доступа к кортежу ключей, добавленного для #8285, где, по-видимому, по недосмотру был опущен случай использования доступа к срезу.References: #8285
typing¶
Улучшена типизация
RowMapping
, чтобы указать, что она поддерживает такжеColumn
как индексные объекты, а не только строковые имена. Pull request любезно предоставлен Энди Фриландом.References: #9644
postgresql¶
Исправлена критическая регрессия, вызванная функцией #9618, которая изменила архитектуру функции insertmanyvalues для версии 2.0.10, в результате чего значения с плавающей точкой теряли все десятичные знаки при вставке с помощью функции insertmanyvalues в драйверах psycopg2 или psycopg.
References: #9701
mssql¶
Реализован тип
Double
для SQL Server, где он будет отображатьDOUBLE PRECISION
во время DDL. Это реализовано с помощью нового MSSQL-типа данныхDOUBLE_PRECISION
, который также может использоваться напрямую.
oracle¶
В диалектах Oracle исправлена проблема, при которой возвращаемые типы
Decimal
, такие какNumeric
, возвращали значения с плавающей точкой, а не объектыDecimal
, когда эти столбцы использовались в предложенииInsert.returning()
для возврата значений INSERTed.
2.0.10¶
Released: April 21, 2023orm¶
Исправлена ошибка, при которой различные ORM-специфичные геттеры, такие как
ORMExecuteState.is_column_load
,ORMExecuteState.is_relationship_load
,ORMExecuteState.loader_strategy_path
и т.д., выдавали ошибкуAttributeError
, если сам SQL-оператор представлял собой «составной select», например, UNION.This change is also backported to: 1.4.48
References: #9634
Исправлена проблема, при которой модификатор
declared_attr.directive()
некорректно выполнялся для подклассов при применении к имени специального метода__mapper_args__
, в отличие от прямого использованияdeclared_attr
. Эти две конструкции должны иметь идентичное поведение во время выполнения.References: #9625
Внесено усовершенствование в опцию загрузчика
with_loader_criteria()
, позволяющее указывать ее в методеExecutable.options()
оператора верхнего уровня, который сам не является ORM-оператором. Примерами могут служитьselect()
, встроенные в составные операторы, такие какunion()
, внутри конструкцииInsert.from_select()
, а также в выражениях CTE, которые на верхнем уровне не относятся к ORM.References: #9635
Исправлена ошибка в функции массовой вставки ORM, когда при запросе RETURNING отдельных колонок в операторе INSERT выводились дополнительные ненужные колонки.
References: #9685
Исправлена ошибка в декларативных классах данных ORM, когда конструкции
query_expression()
иcolumn_property()
, которые в контексте декларативного отображения документированы как конструкции только для чтения, не могли быть использованы с классомMappedAsDataclass
без добавленияinit=False
, что в случаеquery_expression()
было невозможно, так как не включался параметрinit
. Эти конструкции были модифицированы с точки зрения класса данных так, чтобы они считались «только для чтения», устанавливаяinit=False
по умолчанию и больше не включая их в конструктор pep-681. Параметры класса данныхcolumn_property()
init
,default
,default_factory
,kw_only
теперь устарели; эти поля не применяются кcolumn_property()
, используемым в конфигурации декларативных классов данных, где конструкция будет доступна только для чтения. Также вquery_expression()
добавлен специфический для чтения параметрquery_expression.compare
;query_expression.repr
уже присутствовал.References: #9628
Добавлен недостающий параметр
mapped_column.active_history
в конструкциюmapped_column()
.
engine¶
Добавлены функции
create_pool_from_url()
иcreate_async_pool_from_url()
для создания экземпляраPool
из входного url, переданного в виде строки илиURL
.References: #9613
Устранен существенный недостаток, который был выявлен в функции оптимизации производительности Поведение «Вставка многих значений» для операторов INSERT, впервые появившейся в серии 2.0. Это стало продолжением изменения в версии 2.0.9, которое отключило эту функцию в версии для SQL Server из-за того, что ORM полагалась на кажущееся упорядочивание строк, которое не гарантировано. Исправление применяет новую логику ко всем операциям «insertmanyvalues», которая вступает в силу при появлении нового параметра
Insert.returning.sort_by_parameter_order
в методахInsert.returning()
илиUpdateBase.return_defaults()
, что с помощью комбинации альтернативных форм SQL, прямого соответствия параметрам на стороне клиента и, в некоторых случаях, перехода на выполнение row-at-a-time, позволяет применять сортировку к каждой партии возвращаемых строк, используя соответствие первичному ключу или другим уникальным значениям в каждой строке, которые можно соотнести с входными данными.Ожидается, что влияние на производительность будет минимальным, поскольку практически все распространенные сценарии работы с первичными ключами подходят для упорядоченной по параметрам пакетной обработки для всех бэкендов, кроме SQLite, а режим «row-at-a-time» работает с минимальными накладными расходами на Python по сравнению с очень тяжелыми подходами, использовавшимися в серии 1.x. Для SQLite разницы в производительности при использовании режима «row-at-a-time» нет.
Предполагается, что с помощью эффективного INSERT «row-at-a-time» с возможностью пакетной обработки RETURNING, функция «insertmanyvalues» впоследствии может быть более легко обобщена на сторонние бэкенды, которые включают поддержку RETURNING, но не всегда могут гарантировать соответствие порядку параметров.
typing¶
Добавлена информация о типизации для недавно добавленных операторов
ColumnOperators.icontains()
,ColumnOperators.istartswith()
,ColumnOperators.iendswith()
и побитовых операторовColumnOperators.bitwise_and()
,ColumnOperators.bitwise_or()
,ColumnOperators.bitwise_xor()
,ColumnOperators.bitwise_not()
,ColumnOperators.bitwise_lshift()
ColumnOperators.bitwise_rshift()
. Pull request любезно предоставлен Martijn Pieters.References: #9650
Обновление кодовой базы для перехода на типизацию с Mypy 1.2.0.
Исправлена проблема, из-за которой выражения
PropComparator.and_()
не могли быть корректно набраны внутри опций загрузчика, таких какselectinload()
.References: #9669
postgresql¶
В диалекте asyncpg добавлена опция аргумента соединения
prepared_statement_name_func
. Данная опция позволяет передать вызываемую переменную, используемую для настройки имени подготовленного оператора, который будет создаваться драйвером при выполнении запросов. Pull request любезно предоставлен Павлом Сироткиным.См.также
References: #9608
Добавить недостающий метод
Range.intersection()
. Pull request любезно предоставлен Юрием Карабасом.References: #9509
Восстановлен необязательный параметр
ENUM.name
в сигнатуре дляENUM
, так как он выбирается автоматически из заданного типа pep-435Enum
.References: #9611
Исправлена проблема, при которой сравнение для
ENUM
с обычной строкой приводило к типу правой части VARCHAR, что из-за более явного приведения, добавленного в диалекты, такие как asyncpg, приводило к ошибке несоответствия типов PostgreSQL.References: #9621
Исправлена проблема, из-за которой в PostgreSQL не удавалось отразить индексы на основе выражений с длинными выражениями. Выражение ошибочно усекалось до длины идентификатора (по умолчанию это 63 байта).
References: #9615
mssql¶
Восстановлена функция insertmanyvalues для Microsoft SQL Server. Эта функция была отключена в версии 2.0.9 из-за очевидной зависимости от порядка RETURNING, который не гарантируется. Архитектура функции «insertmanyvalues» была переработана с учетом специфической организации операторов INSERT и обработки строк результатов, гарантирующей соответствие возвращаемых строк вводимым записям.
oracle¶
Исправлена проблема, при которой тип данных
Uuid
не мог быть использован в предложении INSERT..RETURNING в диалекте Oracle.
2.0.9¶
Released: April 5, 2023orm¶
Исправлен бесконечный цикл, который мог возникать при использовании функции «отношение к псевдоклассу», а также при указании в загрузчике рекурсивного ускоренного загрузчика, например
lazy="selectinload"
, в сочетании с другим ускоренным загрузчиком на противоположной стороне. Исправлена проверка на наличие циклов для включения отношений с псевдоклассами.This change is also backported to: 1.4.48
References: #9590
mariadb¶
Добавлено
row_number
как зарезервированное слово в MariaDb.References: #9588
mssql¶
Функция SQLAlchemy «insertmanyvalues», обеспечивающая быструю INSERT многих строк и одновременно поддерживающая RETURNING, временно отключена для SQL Server. Поскольку в настоящее время эта функция используется для сопоставления существующих объектов ORM с возвращаемыми идентификаторами первичного ключа, данный шаблон использования не во всех случаях работает с SQL Server, поскольку порядок строк, возвращаемых «OUTPUT inserted», не всегда совпадает с порядком отправки кортежей, что приводит к принятию ORM неверных решений относительно этих объектов в последующих операциях.
Эта возможность будет вновь включена в ближайшем выпуске и снова будет действовать для многорядных операторов INSERT, однако использование этой возможности в единицах работы будет отключено, возможно, для всех диалектов, если в таблицах, отображаемых на ORM, не будет присутствовать столбец «sentinel», чтобы возвращаемые строки могли быть отнесены к исходным переданным данным.
References: #9603
Изменена стратегия массового INSERT, используемая для SQL Server «executemany» с pyodbc при установке
fast_executemany
в значениеTrue
, путем использованияfast_executemany
/cursor.executemany()
для массового INSERT, не включающего RETURNING, восстанавливая то же поведение, которое использовалось в SQLAlchemy 1.4 при установке этого параметра.Новые данные о производительности, полученные от конечных пользователей, показали, что
fast_executemany
по-прежнему значительно быстрее для очень больших наборов данных, поскольку использует команды ODBC, которые могут получать все строки за один цикл, что позволяет использовать гораздо большие объемы данных, чем пакеты, которые могут быть отправлены командой «insertmanyvalues», как это было реализовано для SQL Server.Хотя это изменение было сделано таким образом, что «insertmanyvalues» продолжала использоваться для INSERT, включающего RETURNING, а также если
fast_executemany
не был установлен, из-за #9603, стратегия «insertmanyvalues» была отключена для SQL Server в любом случае.References: #9586
2.0.8¶
Released: March 31, 2023orm¶
Исключения
TypeError
иValueError
, возникающие в классах данных Python при использовании класса-миксинаMappedAsDataclass
или декоратораregistry.mapped_as_dataclass()
, теперь оборачиваются в оберткуInvalidRequestError
вместе с информационным контекстом сообщения об ошибке, ссылаясь на документацию по классам данных Python как на авторитетный источник справочной информации о причине возникновения исключения.References: #9563
Исправлена проблема в ORM Annotated Declarative, когда использование рекурсивного типа (например, использование вложенного типа Dict) приводило к переполнению рекурсии в логике разрешения аннотаций ORM, даже если этот тип данных не был необходим для отображения колонки.
References: #9553
Исправлена проблема, при которой конструкция
mapped_column()
вызывала внутреннюю ошибку, если использовалась в декларативном миксине и включала параметрmapped_column.deferred
.References: #9550
Расширено предупреждение, выдаваемое при наличии в декларативном отображении простого объекта
column()
, для включения в него произвольного SQL-выражения, не объявленного в соответствующем типе свойств, таких какcolumn_property()
,deferred()
и т.д. В противном случае эти атрибуты вообще не отображаются и остаются неизменными в словаре класса. Поскольку представляется вероятным, что такое выражение обычно не является тем, что предполагается, в данном случае предупреждение выдается для всех таких игнорируемых выражений, а не только для случаяcolumn()
.References: #9537
Исправлена ошибка, при которой обращение к значению выражения гибридного свойства класса, который не был отображен или еще не был отображен (например, обращение к нему в методе
declared_attr()
), приводило к внутренней ошибке, так как внутренняя выборка для маппера родительского класса не выполнялась, а указание на игнорирование этой ошибки было случайно удалено в 2.0.References: #9519
Поля, объявленные в декларативных миксинах и затем объединенные с классами, использующими
MappedAsDataclass
, где эти поля миксинов сами не являются частью класса данных, теперь выдают предупреждение об устаревании, поскольку в будущем выпуске эти поля будут игнорироваться, так как поведение классов данных Python заключается в игнорировании этих полей. В соответствии с pep-681 программы проверки типов не будут видеть эти поля.См.также
При преобразовании <cls> в класс данных, атрибут(ы) происходят из суперкласса <cls>, который не является классом данных. - история обоснования
References: #9350
Исправлена проблема, когда метод
BindParameter.render_literal_execute()
вызывался с ошибкой при вызове параметра, с которым также связаны аннотации ORM. На практике это проявлялось в виде сбоя компиляции SQL при использовании некоторых комбинаций диалекта, использующего «FETCH FIRST», например, Oracle, и конструкцииSelect
, использующейSelect.limit()
, в некоторых ORM-контекстах, в том числе, если оператор был встроен в выражение primaryjoin отношения.References: #9526
В целях обеспечения согласованности с изменениями в модулях работы, сделанными для #5984 и #8862, которые отключают обработку «lazy=“raise“» в процессах
Session
, не вызванных доступом к атрибутам, методSession.delete()
теперь также будет отключать обработку «lazy=“raise“» при прохождении путей отношений для обработки каскадных правил «delete» и «delete-orphan». Ранее не существовало простого способа общего вызоваSession.delete()
на объекте, для которого было установлено «lazy=“raise“» так, чтобы загружались только необходимые отношения. Поскольку «lazy=“raise“» в первую очередь предназначен для отлова SQL-загрузки, возникающей при обращении к атрибутам,Session.delete()
теперь ведет себя так же, как и другие методыSession
, включаяSession.merge()
, а такжеSession.flush()
вместе с autoflush.References: #9549
Исправлена проблема, при которой в классе Declarative mixin нельзя было использовать директиву
Mapped
только для аннотаций, при этом атрибут не пытался вступить в силу для подклассов с одиночным или объединенным наследованием сопоставленных классов, которые уже сопоставили этот атрибут суперклассу, что приводило к конфликтующим ошибкам и/или предупреждениям в колонках.References: #9564
Правильно набирать
Insert.from_select.names
для приема списка строк или столбцов или отображаемых атрибутов.References: #9514
examples¶
Исправлена проблема в примере «история версий», когда использование декларативной базы, производной от
DeclarativeBase
, не приводило к сопоставлению. Кроме того, исправлен приведенный тестовый набор так, что документированная инструкция по выполнению примера с помощью Python unittest теперь снова работает.
typing¶
Исправлена типизация для
deferred()
иquery_expression()
для корректной работы с отображениями стилей 2.0.References: #9536
postgresql¶
Исправлена критическая ошибка в диалектах PostgreSQL, таких как asyncpg, которые полагаются на явные приведения в SQL для корректной передачи типов данных драйверу, когда тип данных
String
приводился вместе с точной длиной сравниваемого столбца, что приводило к неявному усечению при сравненииVARCHAR
меньшей длины со строкой большей длины независимо от используемого оператора (например, LIKE, MATCH и т.д.). Теперь диалект PostgreSQL опускает длину изVARCHAR
при приведении.References: #9511
mysql¶
misc¶
Реализованы недостающие методы
copy
иpop
в классе OrderedSet.References: #9487
2.0.7¶
Released: March 18, 2023typing¶
Исправлена проблема типизации, при которой
composite()
не позволял использовать произвольный вызываемый класс в качестве источника составного класса.References: #9502
postgresql¶
2.0.6¶
Released: March 13, 2023orm¶
Исправлена ошибка, при которой функция «активная история» не была полностью реализована для составных атрибутов, что делало невозможным получение событий, включающих «старое» значение. По-видимому, это происходило и в старых версиях SQLAlchemy, когда «active_history» распространялась на базовые атрибуты, основанные на столбцах, но обработчик событий, прослушивающий сам составной атрибут, не получал заменяемое «старое» значение, даже если в composite() было установлено значение active_history=True.
Кроме того, исправлена локальная для 2.0 регрессия, из-за которой active_history в композите не присваивалась импу с помощью
attr.impl.active_history=True
.References: #9460
Исправлена регрессия, связанная с замариванием строк Python между cython- и чисто Python-реализациями
Row
, которая возникла в ходе рефакторинга кода для версии 2.0 с типизацией. Определенная константа превращалась в строковуюEnum
для чистой Python-версииRow
, в то время как в cython-версии продолжала использоваться целочисленная константа, что приводило к сбоям десериализации.References: #9418
sql¶
Исправлена регрессия, когда исправление для #8098, выпущенное в серии 1.4 и обеспечивающее уровень concurrency-safe проверок для лямбда SQL API, включало дополнительные исправления в патче, которые не удалось применить к основной ветке. Эти дополнительные исправления были применены.
References: #9461
Исправлена ошибка, при которой конструкция
select()
не могла быть выведена на экран, если она не имела столбцов, а затем использовалась в контексте EXISTS, вызывая внутреннее исключение. Хотя пустой «SELECT» обычно не является корректным SQL, в контексте EXISTS такие базы данных, как PostgreSQL, допускают его, и в любом случае условие теперь не вызывает внутреннего исключения.References: #9440
typing¶
Исправлена проблема типизации, при которой
ColumnElement.cast()
не допускал аргументаTypeEngine
, не зависящего от типа самогоColumnElement
, что является цельюColumnElement.cast()
.References: #9451
Исправлены проблемы, позволяющие проходить тесты типизации под Mypy 1.1.1.
oracle¶
Исправлена ошибка отражения, при которой Oracle «name normalize» не работал корректно при отражении символов, находящихся в схеме «PUBLIC», таких как синонимы, в результате чего имя PUBLIC не могло быть указано в нижнем регистре на стороне Python для аргумента
Table.schema
. Использование заглавной буквы «PUBLIC» работало, но при этом приводило к неудобным SQL-запросам, включающим заключенное в кавычки имя"PUBLIC"
, а также к индексированию таблицы по заглавной букве «PUBLIC», что было непоследовательно.References: #9459
2.0.5.post1¶
Released: March 5, 2023orm¶
Добавлены аргументы конструктора для встроенных типов коллекций отображений, включая
KeyFuncDict
,attribute_keyed_dict()
,column_keyed_dict()
, чтобы эти словарные типы можно было конструировать на месте, предварительно задав данные; это обеспечивает дополнительную совместимость с такими инструментами, как Python dataclasses.asdict()
, которые полагаются на обращение к этим классам непосредственно как к обычным классам словарей.References: #9418
Исправлены многочисленные регрессии, связанные с #8372, включающие
attribute_mapped_collection()
(теперь называетсяattribute_keyed_dict()
).Во-первых, коллекция перестала работать с «ключевыми» атрибутами, которые сами не являлись обычными отображаемыми атрибутами; исправлены атрибуты, связанные с дескрипторами и/или прокси-атрибутами ассоциаций.
Во-вторых, если событию или другой операции требовался доступ к «ключу» для заполнения словаря из сопоставленного атрибута, который не был загружен, то это также приводило к ошибке, а не к попытке загрузить атрибут, как это было в 1.4. Это также исправлено.
Для обоих случаев поведение #8372 было расширено. В #8372 была введена ошибка, возникающая в том случае, если производный ключ, который будет использоваться в качестве ключа сопоставленного словаря, фактически не назначен. В данном изменении предупреждение выдается только в том случае, если эффективное значение атрибута «.key» равно
None
, когда нельзя однозначно определить, было ли этоNone
намеренным или нет. В дальнейшемNone
не будет поддерживаться в качестве ключей словарей сопоставленных коллекций (так как обычно ссылается на NULL, что означает «неизвестно»). Установкаattribute_keyed_dict.ignore_unpopulated_attribute
теперь будет приводить к тому, что такие ключиNone
также будут игнорироваться.References: #9424
Установлено, что диалекты
sqlite
иmssql+pyodbc
теперь совместимы с функцией «версионированные строки» SQLAlchemy ORM, поскольку SQLAlchemy теперь вычисляет rowcount для оператора RETURNING в этом конкретном случае путем подсчета возвращаемых строк, а не полагаясь наcursor.rowcount
. В частности, вариант использования ORM versioned rows (документированный в Настройка счетчика версий) теперь должен полностью поддерживаться диалектом SQL Server pyodbc.Добавлена поддержка применения параметра
Mapper.polymorphic_load
к каждому отображателю в иерархии наследования глубиной более одного уровня, что позволяет загружать колонки для всех классов иерархии, указывающих на"selectin"
, с помощью одного оператора, а не игнорировать элементы промежуточных классов, которые, тем не менее, указывают на то, что они также будут участвовать в загрузке"selectin"
и не являются частью самого базового оператора SELECT.References: #9373
Продолжено исправление для #8853, позволяющее имени
Mapped
быть полностью квалифицированным независимо от наличия или отсутствияfrom __annotations__ import future
. Эта проблема, впервые исправленная в версии 2.0.0b3, подтвердила работоспособность данного случая через набор тестов, однако набор тестов, очевидно, не проверял поведение для имениMapped
вообще не присутствующего локально; разрешение строк было обновлено для обеспечения локальности символаMapped
, что относится к тому, как ORM использует эти функции.
orm declarative¶
Исправлена проблема, при которой новый параметр
mapped_column.use_existing_column
не работал, если два одноименных столбца были отображены под именами атрибутов, которые отличались от явного имени, заданного самому столбцу. Теперь при использовании этого параметра имена атрибутов могут быть разными.References: #9332
engine¶
Небольшая оптимизация реализации
Result
в Cython, использующая cdef для конкретного значения int, чтобы избежать накладных расходов на Python. Pull request любезно предоставлен Матусом Вало.References: #9343
Исправлена ошибка, при которой объекты
Row
не могли надежно распаковываться между процессами из-за случайного использования нестабильного хэш-значения.References: #9423
sql¶
Восстановление старых функций
nullslast()
иnullsfirst()
в пространстве имен импортаsqlalchemy
. Ранее новые функцииnulls_last()
иnulls_first()
были доступны, а старые были непреднамеренно удалены.References: #9390
schema¶
Убедиться, что при предоставлении аргумента
MetaData.schema
аргументMetaData
является строкой.
typing¶
Экспорт типа, возвращаемого
scoped_session.query_property()
, с использованием нового публичного типаQueryPropertyDescriptor
.References: #9338
Исправлена ошибка, при которой метод
Connection.scalars()
не типизировался как позволяющий создавать список с несколькими параметрами, что теперь поддерживается с помощью операций insertmanyvalues.Улучшена типизация отображения, передаваемого в
Insert.values()
иUpdate.values()
, для более свободного выбора типа коллекции: вместо WriteableDict
указывается read-onlyMapping
, что приводит к ошибке при слишком ограниченном типе ключа.References: #9376
Добавлена недостающая перегрузка init для объекта типа
Numeric
, чтобы программы проверки типов pep-484 могли правильно определять полный тип, определяя по параметруNumeric.asdecimal
, будут ли представлены объектыDecimal
илиfloat
.References: #9391
Исправлена ошибка типизации, при которой
Select.from_statement()
не принимал в качестве допустимого типа объектыtext()
илиTextualSelect
. Дополнительно исправлен тип возврата методаcolumns
, который отсутствовал.References: #9398
Исправлена проблема ввода, при которой
with_polymorphic()
не записывал корректно тип класса.References: #9340
postgresql¶
Исправлена проблема в PostgreSQL
ExcludeConstraint
, когда литеральные значения компилировались как связанные параметры, а не как прямые инлайн-значения, как это требуется для DDL.References: #9349
Исправлена проблема, при которой конструкция PostgreSQL
ExcludeConstraint
не копировалась в операциях типаTable.to_metadata()
, а также в некоторых сценариях Alembic, если ограничение содержало элементы текстового выражения.References: #9401
mysql¶
Поддержка пула ping-слушателей для получения событий исключений через событие
DialectEvents.handle_error()
, добавленная в 2.0.0b1 для #5648, не учитывала специфические для диалектов ping-процедуры, такие как MySQL и PostgreSQL. Функция диалектов была переработана таким образом, чтобы все диалекты участвовали в обработке событий. Кроме того, добавлен новый булевский элементExceptionContext.is_pre_ping
, который определяет, выполняется ли данная операция в рамках предварительного пинга.В этом выпуске сторонние диалекты, реализующие пользовательский метод
Dialect.do_ping()
, могут перейти на новое улучшенное поведение: их метод больше не будет перехватывать исключения или проверять исключения на «is_disconnect», а просто будет распространять все исключения наружу. Проверка исключения на «is_disconnect» теперь выполняется с помощью вложенного метода в диалекте по умолчанию, который гарантирует, что крючок событий будет вызван для всех сценариев исключений, прежде чем проверить исключение как исключение «disconnect». Если существующий методdo_ping()
продолжает перехватывать исключения и проверять «is_disconnect», он будет продолжать работать, как и раньше, но крючкиhandle_error
не будут иметь доступа к исключению, если оно не будет распространено наружу.References: #5648
sqlite¶
Исправлена регрессия для соединений SQLite, когда использование параметра
deterministic
при создании функций базы данных приводило к ошибке для старых версий SQLite, предшествующих версии 3.8.3. Для этого случая была улучшена логика проверки версии.References: #9379
mssql¶
Исправлена проблема в новом типе данных
Uuid
, из-за которой он не работал с драйвером pymssql. Поскольку pymssql, похоже, снова поддерживается, восстановлено тестирование поддержки pymssql.References: #9414
Настроен диалект pymssql, чтобы лучше использовать RETURNING для операторов INSERT для получения последних вставленных значений первичного ключа, аналогично тому, как это происходит в диалекте mssql+pyodbc в настоящее время.
misc¶
Исправлена проблема в automap, когда вызов
AutomapBase.prepare()
из определенного сопоставленного класса, а не изAutomapBase
напрямую, не использовал правильный базовый класс при обнаружении новых таблиц, а использовал заданный класс, что приводило к попыткам мапперов настроить наследование. Хотя, как правило, в любом случае следует вызыватьAutomapBase.prepare()
из базы, она не должна так плохо вести себя при вызове из подкласса.References: #9367
Исправлена регрессия, вызванная добавлением в
sqlalchemy.ext.mutable
типизации для #8667, при которой семантика метода.pop()
изменялась таким образом, что метод становился нерабочим. Pull request любезно предоставлен Nils Philippsen.References: #9380
2.0.4¶
Released: February 17, 2023orm¶
Для адаптации изменения порядка следования столбцов, используемого ORM Declarative в SQLAlchemy 2.0, был добавлен новый параметр
mapped_column.sort_order
, который может быть использован для управления порядком следования столбцов, определенных в таблице ORM, для таких распространенных случаев использования, как миксины с первичными ключевыми столбцами, которые должны появляться первыми в таблицах. Примечания к изменениям в Декларативный ORM применяет порядок столбцов по-разному; управление поведением с помощью sort_order иллюстрируют изменение порядка по умолчанию (которое является частью всех релизов SQLAlchemy 2.0), а также использованиеmapped_column.sort_order
для управления порядком колонок при использовании миксинов и нескольких классов (новое в 2.0.4).См.также
Декларативный ORM применяет порядок столбцов по-разному; управление поведением с помощью sort_order
References: #9297
Метод
Session.refresh()
теперь будет немедленно загружать связанный с отношениями атрибут, явно названный в коллекцииSession.refresh.attribute_names
, даже если он в данный момент связан с загрузчиком «select», который обычно является «ленивым» загрузчиком, не срабатывающим при обновлении. Теперь стратегия «ленивого загрузчика» будет определять, что операцияSession.refresh()
, инициированная пользователем, явно именует этот атрибут, и будет вызывать стратегию «немедленной загрузки» для выполнения SQL-запроса на загрузку атрибута. Это может быть полезно, в частности, для некоторых ситуаций в asyncio, когда необходимо принудительно загрузить незагруженный атрибут lazy-loaded, без использования собственно шаблона lazy-loading, не поддерживаемого в asyncio.References: #9298
Исправлена регрессия, появившаяся в версии 2.0.2 из-за #9217, когда использование операторов DML RETURNING, а также конструкций
Select.from_statement()
, как это было «исправлено» в #9217, в сочетании с ORM mapped классами, использующими выражения, например,column_property()
, приводило к внутренней ошибке в Core, когда он пытался сопоставить выражение по имени. Данное исправление устраняет проблему в Core, а также корректирует исправление в #9217 так, чтобы оно не действовало для случая использования DML RETURNING, где оно добавляет ненужные накладные расходы.References: #9273
Пометили внутренний модуль
EvaluatorCompiler
как приватный для ORM и переименовали его в_EvaluatorCompiler
. Для пользователей, которые могли полагаться на это, имяEvaluatorCompiler
по-прежнему присутствует, однако его использование не поддерживается и будет удалено в будущем выпуске.
orm declarative¶
Добавлен новый параметр
dataclasses_callable
как в классMappedAsDataclass
, так и в методregistry.mapped_as_dataclass()
, который позволяет использовать для создания классов данных альтернативный вызов Pythondataclasses.dataclass
. В данном случае вместо него используется функция Pydantic для создания dataclass. В версию 2.0.1 была внесена корректировка в поддержку миксинов, добавленных для #9179, так что коллекция__annotations__
миксина переписана так, чтобы не включать контейнерMapped
, подобно тому, как это происходит с отображаемыми классами, чтобы конструктор Pydantic dataclasses не подвергался воздействию неизвестных типов.References: #9266
sql¶
Исправлена проблема, при которой типы элементов кортежа-значения жестко кодировались так, чтобы принимать типы из сравниваемого кортежа, когда для сравнения использовался оператор
ColumnOperators.in_()
. Это не соответствовало обычному способу определения типов для бинарных выражений, согласно которому сначала рассматривается тип элемента в правой части, а затем применяется тип в левой части.References: #9313
Добавлено публичное свойство
Table.autoincrement_column
, возвращающее столбец, идентифицированный как автоинкрементный в столбце.References: #9277
typing¶
Улучшена поддержка типизации для расширения Атрибуты гибрида, обновлена вся документация для использования ORM Annotated Declarative mappings, добавлен новый модификатор
hybrid_property.inplace
. Этот модификатор позволяет изменять состояниеhybrid_property
на месте, что, по сути, и делали ранние версии гибридов, пока в SQLAlchemy версии 1.2.0 #3912 не было изменено на удаление мутации на месте. Теперь мутация на месте восстанавливается на основе opt-in, чтобы позволить одному гибриду иметь несколько методов, без необходимости называть все методы одинаково и без необходимости тщательно «выстраивать цепочки» методов с разными именами для сохранения композиции. Такие инструменты типизации, как Mypy и Pyright, не позволяют использовать одноименные методы в классе, поэтому с помощью данного изменения восстанавливается простой способ создания гибридов с поддержкой типизации.References: #9321
oracle¶
Скорректировано поведение параметра
thick_mode
для диалекта python-oracledb, чтобы он корректно принимал значениеFalse
. Ранее толькоNone
указывал на то, что толстый режим должен быть отключен.References: #9295
2.0.3¶
Released: February 9, 2023sql¶
Исправлена критическая ошибка в формулировке SQL-выражений в серии 2.0, связанная с использованием #7744, что улучшило поддержку SQL-выражений, содержащих множество элементов против одного и того же оператора многократно; группировка скобок терялась при использовании элементов выражения, выходящих за пределы первых двух элементов.
References: #9271
typing¶
2.0.2¶
Released: February 6, 2023orm¶
Добавлен новый крючок событий
MapperEvents.after_mapper_constructed()
, который предоставляет крючок событий, происходящих сразу после полного построения объектаMapper
, но до вызоваregistry.configure()
. Это позволяет коду создавать дополнительные отображения и структуры таблиц на основе начальной конфигурацииMapper
, что также интегрируется в конфигурацию Declarative. Ранее при использовании Declarative, где объектMapper
создается в процессе создания класса, не существовало документированных средств для запуска кода в этот момент. Это изменение сразу же должно принести пользу пользовательским схемам отображения, таким как в примере Версионирование с помощью таблицы истории, которые генерируют дополнительные отображатели и таблицы в ответ на создание отображаемых классов.References: #9220
Редко используемые атрибут
Mapper.iterate_properties
и методMapper.get_property()
, которые в основном используются внутри компании, больше не вызывают неявно процессregistry.configure()
. Публичный доступ к этим методам осуществляется крайне редко, и единственным преимуществом наличияregistry.configure()
было бы разрешение на присутствие в этих коллекциях свойств «обратной ссылки». Для поддержки нового событияMapperEvents.after_mapper_constructed()
итерация и доступ к внутренним объектамMapperProperty
теперь возможны без инициирования неявной конфигурации самого отображателя.Более публичный путь к итерации всех атрибутов отображения, коллекция
Mapper.attrs
и подобные ей, по-прежнему будет неявно вызывать шагregistry.configure()
, делая доступными атрибуты backref.Во всех случаях
registry.configure()
всегда доступен для прямого вызова.References: #9220
Исправлена неясная проблема наследования ORM, вызванная #8705, когда в некоторых сценариях наследования отображателей, указывающих под
column_property()
группы колонок из локальной таблицы и наследуемой таблицы вместе, тем не менее, выдавалось предупреждение о неявном объединении одноименных свойств.References: #9232
Исправлена ошибка, при которой использование функции
Mapper.version_id_col
с обычным инкрементирующим столбцом на стороне Python не работало для SQLite и других баз данных, не поддерживающих «rowcount» с «RETURNING», поскольку для таких столбцов предполагалось «RETURNING», хотя на самом деле этого не происходило.References: #9228
Исправлена регрессия при использовании
Select.from_statement()
в контексте ORM, когда для ORM-выражений, не являющихся полностью текстовыми, было запрещено сопоставление столбцов с SQL-метками, основанными только на имени. Это приводило к тому, что произвольные SQL-выражения с метками в виде имен столбцов не могли соответствовать загружаемой сущности, что ранее работало в версии 1.4 и предыдущих, поэтому прежнее поведение восстановлено.References: #9217
orm declarative¶
Исправлена регрессия, вызванная исправлением #9171, которое само по себе исправляло регрессию, связанную с механикой применения
__init__()
к классам, расширяемым изDeclarativeBase
. Это изменение приводило к тому, что__init__()
применялся к пользовательской базе, если непосредственно в классе не было метода__init__()
. Это было исправлено таким образом, что__init__()
применяется только в том случае, если ни один другой класс в иерархии определяемой пользователем базы не имеет метода__init__()
. Это снова позволяет определяемым пользователем базовым классам, основанным наDeclarativeBase
, включать в себя миксины, которые сами включают в себя пользовательский метод__init__()
.References: #9249
Исправлена проблема в отображениях декларативных классов данных ORM, связанная с добавленной в 2.0.1 поддержкой миксинов через #9179, когда сочетание использования миксинов и наследования ORM в некоторых случаях неправильно классифицировало поля, что приводило к потере аргументов класса данных на уровне полей, таких как
init=False
.References: #9226
Исправлены декларативные связки ORM, позволяющие указывать параметр
Mapper.primary_key
внутри__mapper_args__
при использованииmapped_column()
. Несмотря на то, что этот вариант использования был прямо указан в документации 2.0,Mapper
не принимал конструкциюmapped_column()
в этом контексте. Эта возможность уже работала для параметровMapper.version_id_col
иMapper.polymorphic_on
.В рамках этого изменения атрибут
__mapper_args__
может быть указан без использованияdeclared_attr()
на не маппированном классе mixin, включая запись"primary_key"
, которая ссылается на объектыColumn
илиmapped_column()
, локально присутствующие на mixin; Declarative также переведет эти колонки в правильные для конкретного маппированного класса. Это уже работало для параметровMapper.version_id_col
иMapper.polymorphic_on
. Кроме того, элементы внутри"primary_key"
могут быть указаны как строковые имена существующих маппируемых свойств.References: #9240
При попытке совмещения использования
MappedAsDataclass
иregistry.mapped_as_dataclass()
в рамках одной иерархии классов возникает явная ошибка, поскольку в этом случае функция класса данных применяется к отображаемому классу в неправильное время, что приводит к ошибкам в процессе отображения.References: #9211
examples¶
Переработан Версионирование с помощью таблицы истории для работы с версией 2.0, в то же время улучшена общая работа примера для использования более новых API, включая недавно добавленный хук
MapperEvents.after_mapper_constructed()
.References: #9220
sql¶
Добавлен полный набор новых побитовых операторов SQL для выполнения побитовых выражений на стороне базы данных над соответствующими значениями данных, такими как целые числа, битовые строки и т.п. Pull request любезно предоставлен Егором Статкевичем.
См.также
References: #8780
asyncio¶
Исправлена регрессия, вызванная исправлением #8419, которая приводила к сбросу asyncpg-соединений (т.е. вызову транзакции
rollback()
) и их нормальному возврату в пул в случае, когда соединение не было явно возвращено в пул соединений, а вместо этого перехватывалось сборщиком мусора Python, что при вызове операции сборки мусора вне цикла событий asyncio приводило к большому количеству трассировки стека, выводимой в лог и стандартный вывод.Восстановлено корректное поведение, при котором все asyncio-соединения, которые собираются в мусор из-за того, что не были явно возвращены в пул соединений, отделяются от пула и отбрасываются с предупреждением, а не возвращаются в пул, поскольку их невозможно надежно сбросить. В случае asyncpg-соединений будет использоваться специфический для asyncpg-соединений метод
terminate()
для более изящного завершения соединения в рамках этого процесса, а не просто для его сброса.Это изменение включает в себя небольшое изменение поведения, которое, как ожидается, будет полезно для отладки asyncio-приложений. Предупреждение, выдаваемое в случае неожиданной сборки мусора в asyncio-соединениях, стало немного агрессивнее за счет переноса его за пределы блока
try/except
и в блокfinally:
, где оно будет выдаваться безусловно, независимо от того, удалась операция отсоединения/завершения или нет. Это также приведет к тому, что приложения и тестовые пакеты, которые переводят предупреждения Python в исключения, будут воспринимать это как полное повышение исключения, в то время как ранее было невозможно, чтобы это предупреждение распространялось как исключение. Приложениям и тестовым пакетам, которым необходимо терпеть это предупреждение в промежуточный период, следует настроить фильтр предупреждений Python таким образом, чтобы эти предупреждения не поднимались.Поведение традиционных синхронных соединений остается неизменным: соединения, собранные в пул, продолжают нормально возвращаться в пул без выдачи предупреждения. Вероятно, в будущем мажорном выпуске это будет изменено, чтобы, по крайней мере, выдавалось предупреждение, аналогичное тому, что выдается для драйверов asyncio, поскольку перехват собранных в пул соединений сборщиком мусора без их корректного возврата в пул является ошибкой использования.
References: #9237
mysql¶
Исправлена регрессия, вызванная выпуском #9058, в котором диалект MySQL
has_table()
был настроен на повторное использование «DESCRIBE», где специфический код ошибки, выдаваемый MySQL версии 8 при использовании несуществующего имени схемы, был неожиданным и не мог быть интерпретирован как булевский результат.References: #9251
Добавлена поддержка нового синтаксиса MySQL 8
AS <name> ON DUPLICATE KEY
при использованииInsert.on_duplicate_key_update()
, который необходим для новых версий MySQL 8, поскольку прежний синтаксисVALUES()
в этих версиях выдает предупреждение об устаревании. Определение версии сервера используется для определения того, следует ли использовать традиционный синтаксис MariaDB / MySQL <8VALUES()
, а не более новый синтаксис, требуемый MySQL 8. Pull request любезно предоставлен Caspar Wylie.References: #8626
sqlite¶
Исправлена функция
has_table()
диалекта SQLite, которая корректно сообщает False для запросов, включающих имя схемы не None для несуществующей схемы; ранее выдавалась ошибка базы данных.References: #9251
2.0.1¶
Released: February 1, 2023orm¶
Исправлена ошибка, при которой в ORM-моделях, использующих наследование объединенных таблиц с составным внешним ключом, возникала внутренняя ошибка во внутреннем устройстве mapper.
References: #9164
Улучшено сообщение об ошибке при связывании опций стратегии из базового класса с другим атрибутом, находящимся вне подкласса, где следует использовать
of_type()
. Ранее при использованииLoad.options()
в сообщении отсутствовала информативная информация о том, что следует использоватьof_type()
, чего не происходило при непосредственном связывании опций. Теперь информационная информация выдается даже при использованииLoad.options()
.References: #9182
orm declarative¶
Добавлена поддержка PEP 484
NewType
для использования вregistry.type_annotation_map
, а также внутри конструкцийMapped
. Эти типы будут вести себя так же, как сейчас пользовательские подклассы типов; они должны явно появляться вregistry.type_annotation_map
, чтобы быть отображенными.References: #9175
При использовании суперкласса
MappedAsDataclass
все классы в иерархии, являющиеся подклассами этого класса, теперь будут проходить через функцию@dataclasses.dataclass
независимо от того, отображены они или нет, так что при превращении отображенных подклассов в классы данных будут использоваться поля не-ORM, объявленные в не отображенных классах иерархии. Это поведение распространяется как на промежуточные классы, отображаемые с помощью__abstract__ = True
, так и на саму пользовательскую декларативную базу, при условии, чтоMappedAsDataclass
присутствует в качестве суперкласса для этих классов.Это позволяет использовать не отображаемые атрибуты, такие как объявления
InitVar
в суперклассах, без необходимости явного запуска декоратора@dataclasses.dataclass
для каждого не отображаемого класса. Новое поведение считается корректным, поскольку именно этого ожидает реализация PEP 681 при использовании суперкласса для указания поведения класса данных.References: #9179
Добавлена поддержка PEP 586
Literal[]
для использования вregistry.type_annotation_map
, а также внутри конструкцийMapped
. Для использования пользовательских типов, таких как эти, они должны явно присутствовать вregistry.type_annotation_map
, которые будут сопоставлены. Pull request любезно предоставлен Фредериком Аалундом.В рамках этого изменения поддержка
Enum
вregistry.type_annotation_map
была расширена, и в дополнение к типам данных была добавлена поддержкаLiteral[]
типов, состоящих из строковых значений, которые будут использоваться в дополнение кenum.Enum
типам данных. Если внутриMapped[]
используетсяLiteral[]
тип данных, не связанный вregistry.type_annotation_map
с конкретным типом данных, то по умолчанию будет использоватьсяEnum
.References: #9187
Исправлена проблема, связанная с использованием
Enum
внутриregistry.type_annotation_map
, когда параметрEnum.native_enum
некорректно копировался в сопоставленный тип данных столбца, если переопределить, как указано в документации, значение этого параметра на False.References: #9200
Исправлена ошибка в классе
DeclarativeBase
, когда конструктор реестра по умолчанию не применялся к самой базе, что отличается от работы предыдущей конструкцииdeclarative_base()
. Это не позволяло сопоставленному классу с собственным методом__init__()
вызыватьsuper().__init__()
для доступа к конструктору по умолчанию реестра и автоматического заполнения атрибутов, а вместо этого вызыватьobject.__init__()
, что приводило к появлениюTypeError
при любых аргументах.References: #9171
Улучшен набор правил для интерпретации типов PEP 593
Annotated
при использовании аннотированного декларативного отображения, внутренний тип будет проверяться на «Optional» во всех случаях, что будет добавлено к критерию, по которому столбец устанавливается как «nullable» или нет; если тип внутри контейнераAnnotated
является опциональным (или объединенным сNone
), столбец будет считаться nullable, если нет явныхmapped_column.nullable
параметров, переопределяющих его.References: #9177
sql¶
Исправление для #7664, выпущенное в версии 2.0.0, включает также
DropSchema
, который был случайно пропущен в этом исправлении, что позволяет выполнять стрингтификацию без диалекта. Исправления для обеих конструкций перенесены в серию 1.4 начиная с версии 1.4.47.References: #7664
Исправлена регрессия, связанная с реализацией новой функции «insertmanyvalues», когда внутренняя
TypeError
возникала в схемах, гдеinsert()
ссылался на внутри другогоinsert()
через CTE; сделаны дополнительные исправления для этого случая использования позиционных диалектов, таких как asyncpg, при использовании «insertmanyvalues».References: #9173
typing¶
Открыл возможность вводить в
Select.with_for_update.of
также аргументы table и mapped class, как это, по-видимому, доступно для диалекта MySQL.References: #9174
Исправлена типизация методов ограничения/смещения, включая
Select.limit()
,Select.offset()
,Query.limit()
,Query.offset()
, чтобы разрешитьNone
, который является документированным API для «отмены» текущего ограничения/смещения.References: #9183
Исправлена проблема типизации, при которой объекты
mapped_column()
, типизированные какMapped
, не принимались в ограничениях схемы, таких какForeignKey
,UniqueConstraint
илиIndex
.References: #9170
Исправлена типизация
ColumnElement.cast()
для принятияType[TypeEngine[T]]
иTypeEngine[T]
; ранее принималось толькоTypeEngine[T]
. Pull request любезно предоставлен Юрием Карабасом.References: #9156
2.0.0¶
Released: January 26, 2023orm¶
Улучшено уведомление о предупреждениях, выдаваемых в процессе configure mappers или flush, которые часто вызываются как часть другой операции, для добавления дополнительного контекста к сообщению, указывающего на одну из этих операций как источник предупреждения в рамках операций, которые могут быть неочевидно связаны.
References: #7305
orm extensions¶
В API горизонтального шардинга добавлена новая опция
set_shard_id
, устанавливающая эффективный идентификатор шарда для запроса, как для первичного запроса, так и для всех вторичных загрузчиков, включая загрузчики с нетерпеливой загрузкой отношений, а также загрузчики с нетерпеливой загрузкой отношений и столбцов.References: #7226
В
AutomapBase
добавлена возможность автозагрузки классов по нескольким схемам, имена которых могут пересекаться, с помощью параметраAutomapBase.prepare.modulename_for_table
, позволяющего настраивать атрибут__module__
вновь создаваемых классов, а также новой коллекцииAutomapBase.by_module
, хранящей разделенное точками пространство имен модулей, связанных с классами на основе атрибута__module__
.Кроме того, метод
AutomapBase.prepare()
теперь может быть вызван любое количество раз, как с включенным отражением, так и без него; при каждом вызове будут обрабатываться только вновь добавленные таблицы, которые ранее не были отображены. Ранее методMetaData.reflect()
необходимо было каждый раз вызывать явно.См.также
Генерация отображений из нескольких схем - иллюстрирует использование сразу двух техник.
References: #5145
sql¶
Исправлена ошибка stringify для DDL-конструкции
CreateSchema
, которая при строке без диалекта выдавала ошибкуAttributeError
. Обновление: Обратите внимание, что это исправление не учитывалоDropSchema
; последующее исправление в версии 2.0.1 исправляет этот случай. Исправление для обоих элементов перенесено в версию 1.4.47.References: #7664
typing¶
Добавлена типизация для встроенных общих функций, доступных из пространства имен
func
, которые принимают определенный набор аргументов и возвращают определенный тип, например, дляcount
,current_timestamp
и т.д.References: #9129
Исправлен тип, передаваемый для «лямбда-операторов», так что обычная лямбда принимается mypy, pyright и другими без ошибок о типах аргументов. Дополнительно реализована типизация большей части публичного API для лямбда-операторов и обеспечена принадлежность
StatementLambdaElement
к иерархииExecutable
, чтобы он типизировался как принимаемыйConnection.execute()
.References: #9120
Методы
ColumnOperators.in_()
иColumnOperators.not_in()
типизированы и включают в себяIterable[Any]
, а неSequence[Any]
для большей гибкости в выборе типа аргумента.References: #9122
Функции
or_()
иand_()
с точки зрения типизации требуют наличия первого аргумента, однако эти функции по-прежнему принимают нулевые аргументы, о чем во время выполнения будет выдано предупреждение об устаревании. Также добавлена поддержка передачи фиксированного литералаFalse
дляor_()
иTrue
дляand_()
только в качестве первого аргумента, однако в документации теперь указывается, что в этих случаях в качестве более явного подхода следует передавать конструкцииfalse()
иtrue()
.References: #9123
Исправлена проблема типизации, когда итерация над объектом
Query
была некорректной.References: #9125
Исправлена проблема, при которой тип объекта при использовании
Result
в качестве менеджера контекста не сохранялся, указывая во всех случаяхResult
, а не конкретный подтипResult
. Pull request любезно предоставлен Martin Baláž.References: #9136
Исправлена проблема, при которой использование параметра
relationship.remote_side
и подобных ему, передавая аннотированный декларативный объект, типизированный какMapped
, не принималось программой проверки типов.References: #9150
Добавлена типизация для старых операторов, таких как
isnot()
,notin_()
и т.д., которые ранее ссылались на новые операторы, но сами не были типизированы.References: #9148
postgresql¶
В диалект asyncpg добавлена поддержка возврата значения
cursor.rowcount
для операторов SELECT, если оно доступно. Хотя это не является типичным использованиемcursor.rowcount
, другие диалекты PostgreSQL обычно предоставляют это значение. Pull request любезно предоставлен Майклом Горвеном.This change is also backported to: 1.4.47
References: #9048
mysql¶
Добавлена поддержка отражения индексов MySQL для корректного отражения словаря
mysql_length
, который ранее игнорировался.This change is also backported to: 1.4.47
References: #9047
mssql¶
Новая возможность отражения и отображения комментариев в диалекте MSSQL, добавленная в #7844, теперь будет отключена по умолчанию, если не удастся определить, что используется неподдерживаемый бэкенд, например Azure Synapse; этот бэкенд не поддерживает комментарии к таблицам и столбцам и не поддерживает процедуры SQL Server, используемые для их генерации и отражения. В диалект добавлен новый параметр
supports_comments
, который по умолчанию имеет значениеNone
, указывающее на то, что поддержка комментариев должна определяться автоматически. При установке значенияTrue
илиFalse
поддержка комментариев либо включается, либо отключается безусловно.См.также
References: #9142
2.0.0rc3¶
Released: January 18, 2023orm¶
В директиве
Mapper
добавлен новый параметрMapper.polymorphic_abstract
. Эта директива предназначена для того, чтобы ORM не считала класс инстанцированным или загруженным напрямую, а только подклассы. Фактический эффект заключается в том, чтоMapper
будет препятствовать прямому инстанцированию экземпляров класса и будет ожидать, что класс не имеет определенной полиморфной идентичности.На практике класс, сопоставленный с помощью
Mapper.polymorphic_abstract
, может использоваться как цельrelationship()
, а также применяться в запросах; подклассы, разумеется, должны включать в свои сопоставления полиморфные тождества.Новый параметр автоматически применяется к классам, которые являются подклассами класса
AbstractConcreteBase
, поскольку этот класс не предназначен для инстанцирования.References: #9060
Исправлена проблема, при которой использование типа pep-593
Annotated
вregistry.type_annotation_map
, который сам содержал общий простой контейнер или типcollections.abc
(например,list
,dict
,collections.abc.Sequence
и т.д.) в качестве целевого типа, приводило к внутренней ошибке, когда ORM пытались интерпретировать экземплярAnnotated
.References: #9099
Добавлено сообщение об ошибке при сопоставлении
relationship()
с абстрактным типом контейнера, напримерMapped[Sequence[B]]
, без указания параметраrelationship.container_class
, который необходим, когда тип является абстрактным. Ранее абстрактный контейнер пытался быть инстанцирован на более позднем шаге и терпел неудачу.References: #9100
sql¶
Исправлена ошибка/регрессия, при которой использование
bindparam()
с тем же именем, что и столбец, в методеUpdate.values()
вUpdate
, а также в методеInsert.values()
вInsert
только в версии 2.0 в некоторых случаях приводило к тому, что SQL-выражение, в котором был представлен параметр, не выполнялось, заменяясь новым параметром с тем же именем и отбрасывая все остальные элементы SQL-выражения, такие как SQL-функции и т.д. В данном случае речь идет об операторах, построенных на основе сущностей ORM, а не простых экземпляровTable
, но это может произойти и в том случае, если оператор был вызван с помощьюSession
илиConnection
.Update
часть проблемы присутствовала как в 2.0, так и в 1.4 и перенесена в 1.4.This change is also backported to: 1.4.47
References: #9075
typing¶
Исправления в аннотациях расширения
sqlalchemy.ext.hybrid
для более эффективной типизации пользовательских методов. При типизации теперь используются возможности PEP 612, поддерживаемые последними версиями Mypy, для сохранения сигнатур аргументов дляhybrid_method
. Возвращаемые значения для гибридных методов принимаются как SQL-выражения в таких контекстах, какSelect.where()
, при этом сохраняется поддержка SQL-методов.References: #9096
mypy¶
В плагин mypy внесены коррективы, учитывающие некоторые потенциальные изменения, которые могут быть внесены в проблему #236 sqlalchemy2-stubs при использовании SQLAlchemy 1.4. Эти изменения синхронизируются с SQLAlchemy 2.0. Изменения также обратно совместимы со старыми версиями sqlalchemy2-stubs.
This change is also backported to: 1.4.47
Исправлен сбой в плагине mypy, который мог произойти как в версии 1.4, так и в версии 2.0, если использовался декоратор для декоратора
mapped()
, на который ссылалось выражение, содержащее более двух компонентов (например,@Backend.mapper_registry.mapped
). Теперь этот сценарий игнорируется; при использовании плагина выражение декоратора должно быть двухкомпонентным (т.е.@reg.mapped
).This change is also backported to: 1.4.47
References: #9102
postgresql¶
Исправлена регрессия, в результате которой в версии 3.1.8 в вызове API psycopg3 было изменено ожидание определенного типа объекта, которое ранее не соблюдалось, что нарушало связь с диалектом psycopg3.
References: #9106
oracle¶
2.0.0rc2¶
Released: January 9, 2023orm¶
Исправлена проблема, связанная с тем, что в версии 2.0 было добавлено слишком ограничительное правило отображения ORM, которое не позволяло выполнять отображение на объекты
TableClause
, например, на те, которые используются в рецепте представления на вики.References: #9071
typing¶
В принятой версии PEP 681 аргумент Data Class Transforms
field_descriptors
был переименован вfield_specifiers
.References: #9067
postgresql¶
Реализованы недостающие операции
JSONB
:@@
используяComparator.path_match()
@?
используяComparator.path_exists()
#-
используяComparator.delete_path()
Pull request curtesy of Guilherme Martins Crocetti.
References: #7147
mysql¶
Восстановлено поведение
Inspector.has_table()
для сообщения о временных таблицах для MySQL / MariaDB. В настоящее время это поведение характерно для всех остальных диалектов, но было удалено для MySQL в версии 1.4 в связи с тем, что команда DESCRIBE больше не используется; в этой или предыдущей версии не было документированной поддержки для сообщения о временных таблицах методомInspector.has_table()
, поэтому предыдущее поведение было неопределенным.Поскольку в SQLAlchemy 2.0 добавлена формальная поддержка состояния временных таблиц через
Inspector.has_table()
, диалект MySQL /MariaDB был возвращен к использованию оператора «DESCRIBE», как это было в серии SQLAlchemy 1.3 и ранее, и добавлена тестовая поддержка такого поведения MySQL / MariaDB. Прежние проблемы с выбросом ROLLBACK, которые пытались решить в версии 1.4, в SQLAlchemy 2.0 не применяются в связи с упрощением обработки транзакцийConnection
.DESCRIBE необходим, так как в MariaDB, в частности, нет какой-либо общедоступной схемы для создания отчетов о временных таблицах, кроме DESCRIBE/SHOW COLUMNS, которые полагаются на выброс ошибки, чтобы сообщить об отсутствии результатов.
References: #9058
oracle¶
Поддерживается вариант использования ограничений по внешнему ключу, когда локальный столбец помечен как «невидимый». Ошибки, обычно генерируемые при создании
ForeignKeyConstraint
, которые проверяют наличие целевого столбца, при отражении отключаются, и ограничение пропускается с предупреждением, аналогично тому, как это уже происходит дляIndex
с подобной проблемой.References: #9059
2.0.0rc1¶
Released: December 28, 2022general¶
Исправлена регрессия, при которой базовый модуль compat обращался к
platform.architecture()
для определения некоторых свойств системы, что приводило к слишком широкому вызову системы по сравнению с вызовом системного уровняfile
, недоступному при некоторых обстоятельствах, в том числе в некоторых конфигурациях безопасного окружения.This change is also backported to: 1.4.46
References: #8995
orm¶
Добавлено новое значение по умолчанию для параметра
Mapper.eager_defaults
«auto», который будет автоматически извлекать значения по умолчанию таблицы во время промывки единицы работы, если диалект поддерживает RETURNING для выполняемого INSERT, а также доступно значение insertmanyvalues. Поспешная выборка значений по умолчанию для UPDATE на стороне сервера, что бывает очень редко, по-прежнему происходит только при установкеMapper.eager_defaults
в значениеTrue
, поскольку для операторов UPDATE не существует формы пакетного RETURNING.References: #8889
Корректировка
Session
с точки зрения расширяемости, а также обновление расширенияShardedSession
:Session.get()
теперь принимаетSession.get.bind_arguments
, что, в частности, может быть полезно при использовании расширения горизонтального шардинга.Session.get_bind()
принимает произвольные аргументы kw, что облегчает разработку кода, использующего классSession
, который переопределяет этот метод с дополнительными аргументами.Добавлена новая опция выполнения ORM
identity_token
, с помощью которой можно напрямую влиять на «токен идентичности», который будет ассоциирован с вновь загруженными объектами ORM. Этот маркер используется в подходах шардинга (в частности,ShardedSession
, но может быть использован и в других случаях) для разделения идентификаторов объектов по разным «шардам».См.также
Событийный крючок
SessionEvents.do_orm_execute()
теперь может использоваться для воздействия на все опции, связанные с ORM, включаяautoflush
,populate_existing
иyield_per
; эти опции повторно обрабатываются после вызова событийных крючков, прежде чем они будут применены. Ранее опции типаautoflush
уже оценивались в этот момент. В этом режиме также поддерживается новая опцияidentity_token
, которая теперь используется расширением горизонтального шардинга.Класс
ShardedSession
заменяет хукShardedSession.id_chooser
новым хукомShardedSession.identity_chooser
, который больше не опирается на устаревший объектQuery
. ВместоShardedSession.id_chooser
по-прежнему принимаетсяShardedSession.identity_chooser
с предупреждением об устаревании.
References: #7837
Поведение «присоединения внешней транзакции к сессии» было пересмотрено и улучшено, что позволяет явно контролировать, как
Session
будет воспринимать входящуюConnection
, которая уже имеет транзакцию и, возможно, точку сохранения. Новый параметрSession.join_transaction_mode
включает в себя ряд опций, которые могут учитывать существующую транзакцию несколькими способами, наиболее важным из которых является то, чтоSession
может работать в полностью транзакционном стиле, используя исключительно точки сохранения, оставляя инициированную извне транзакцию нефиксированной и активной при любых обстоятельствах, что позволяет тестовым наборам откатывать все изменения, происходящие внутри тестов.Кроме того, пересмотрен метод
Session.close()
для полного закрытия точек сохранения, которые еще могут присутствовать, что также позволяет рецепту «внешней транзакции» работать без предупреждений, еслиSession
не завершил явным образом свои собственные транзакции SAVEPOINT.References: #9015
Устранено требование использования атрибута
__allow_unmapped__
в декларативном классе, отображаемом на Dataclass, при обнаружении аннотаций не``Mapped[]``; ранее выдавалось сообщение об ошибке, предназначенное для поддержки устаревших типизированных отображений ORM, в котором дополнительно не упоминались правильные паттерны для использования именно с Dataclass. Теперь это сообщение об ошибке больше не выдается, если используетсяregistry.mapped_as_dataclass()
илиMappedAsDataclass
.References: #8973
Исправлена проблема внутреннего обхода SQL для операторов DML типа
Update
иDelete
, которая приводила, помимо прочих потенциальных проблем, к специфической проблеме использования лямбда-операторов с функцией обновления/удаления ORM.This change is also backported to: 1.4.46
References: #9033
Исправлена ошибка, при которой
Session.merge()
не сохранял текущее загруженное содержимое атрибутов отношений, указанных параметромrelationship.viewonly
, что приводило к нарушению стратегий, использующихSession.merge()
для извлечения полностью загруженных объектов из кэша и других подобных приемов. В связанном с этим изменении исправлена проблема, когда объект, содержащий загруженное отношение, которое, тем не менее, было настроено какlazy='raise'
на отображении, терпел неудачу при передаче вSession.merge()
; теперь проверка на «повышение» приостанавливается в процессе слияния, предполагая, что параметрSession.merge.load
остается по умолчаниюTrue
.В целом это поведенческая корректировка изменения, введенного в серии 1.4 начиная с версии #4994, которое убрало «слияние» из набора каскадов, применяемых по умолчанию к отношениям «только для просмотра». Поскольку отношения «viewonly» не сохраняются ни при каких обстоятельствах, разрешение передачи их содержимого при «merge» не влияет на поведение сохранения целевого объекта. Это позволяет
Session.merge()
корректно использовать один из вариантов его применения - добавление вSession
объектов, которые были загружены в другом месте, часто для восстановления из кэша.This change is also backported to: 1.4.45
References: #8862
Исправлены проблемы в
with_expression()
, когда выражения, состоящие из столбцов, на которые есть ссылки из вложенного SELECT, в некоторых контекстах не выводили корректный SQL, в случае если выражение имело имя метки, совпадающее с атрибутом, который использовалquery_expression()
, даже еслиquery_expression()
не имел выражения по умолчанию. На данный момент, если выражениеquery_expression()
все же имеет выражение по умолчанию, то это имя метки все равно используется по умолчанию, а дополнительная метка с тем же именем будет по-прежнему игнорироваться. В целом, данный случай является довольно сложным, поэтому, возможно, потребуются дополнительные корректировки.This change is also backported to: 1.4.45
References: #8881
Если имя обратной ссылки, используемое в
relationship()
, называет атрибут целевого класса, которому уже присвоено имя метода или атрибута, то выдается предупреждение, поскольку объявление обратной ссылки заменит этот атрибут.References: #4629
Ряд изменений и улучшений, касающихся
Session.refresh()
. Общее изменение заключается в том, что атрибуты первичного ключа объекта теперь включаются в операцию обновления безусловно, если должны быть обновлены атрибуты, связанные с отношениями, даже если срок их действия не истек и если они не указаны в обновлении.Улучшена функция
Session.refresh()
, благодаря которой, если включена автопромывка (как по умолчанию дляSession
), автопромывка происходит в более ранней части процесса обновления, что позволяет применить ожидаемые изменения первичного ключа без возникновения ошибок. Ранее автоочистка происходила слишком поздно, и оператор SELECT не использовал правильный ключ для нахождения строки, в результате чего возникала ошибкаInvalidRequestError
.Когда выполняется описанное выше условие, т.е. в объекте присутствуют непромытые изменения первичного ключа, но автопромывка не включена, метод refresh() теперь явно запрещает выполнение операции, и выдается информационное сообщение
InvalidRequestError
с просьбой сначала промыть непромытые изменения первичного ключа. Ранее такой вариант использования был просто нерабочим, и сообщениеInvalidRequestError
выдавалось в любом случае. Это ограничение сделано для того, чтобы атрибуты первичного ключа были безопасно обновлены, как это необходимо для случая, когда можно обновить объект, при этом также будут выдаваться связанные с отношениями вторичные eagerloader’ы. Это правило применяется во всех случаях, чтобы обеспечить согласованность поведения API независимо от того, нужны ли PK-ключи при обновлении, поскольку необычно обновлять одни атрибуты объекта, оставляя другие атрибуты «в ожидании» в любом случае.Метод
Session.refresh()
был усовершенствован таким образом, что атрибуты, которые связаны сrelationship()
и привязаны к ускоренному загрузчику либо во время отображения, либо через последние использованные опции загрузчика, будут обновляться во всех случаях, даже если передан список атрибутов, не включающий ни одного столбца родительской строки. Это основано на возможности, впервые реализованной для нестолбцовых атрибутов в рамках #1763, исправленной в 1.4, позволяющей нетерпеливо загружаемым атрибутам, связанным отношениями, участвовать в операцииSession.refresh()
. Если в операции обновления не указано ни одного столбца родительской строки, подлежащего обновлению, столбцы первичного ключа, тем не менее, будут включены в операцию обновления, что позволит продолжить загрузку во вторичные загрузчики отношений, как это происходит обычно. Ранее для этого условия возникала ошибкаInvalidRequestError
(#8703)Исправлена проблема, при которой в случае вызова
Session.refresh()
с комбинацией атрибутов с истекшим сроком действия, а также загрузчика, напримерselectinload()
, выполняющего «вторичный» запрос, если атрибуты первичного ключа также находились в истекшем состоянии, выдавался ненужный дополнительный SELECT. Поскольку атрибуты первичного ключа теперь включаются в обновление автоматически, не возникает дополнительной нагрузки на эти атрибуты, когда загрузчик отношений переходит к выборке по ним (#8997)Исправлена регрессия, вызванная выпуском #8126 в версии 2.0.0b1, когда метод
Session.refresh()
выдавал ошибкуAttributeError
, если ему передавалось как имя столбца с истекшим сроком хранения, так и имя атрибута, связанного с отношениями, который был связан с «вторичным» ускоренным загрузчиком, таким какselectinload()
(#8996)
Исправлено исправление, впервые сделанное в версии 1.4 для #8456, которое уменьшало использование внутренних «полиморфных адаптеров», используемых для вывода ORM-запросов при использовании параметра
Mapper.with_polymorphic
. Эти адаптеры, очень сложные и склонные к ошибкам, теперь используются только в тех случаях, когда дляMapper.with_polymorphic
используется явный пользовательский подзапрос, что включает только случай использования конкретных отображений наследования, использующих помощникpolymorphic_union()
, а также унаследованный случай использования алиасированного подзапроса для объединенных отображений наследования, который в современном использовании не нужен.Для наиболее распространенного случая отображений объединенного наследования, использующих встроенную схему полиморфной загрузки, к которым относятся и те, которые используют параметр
Mapper.polymorphic_load
, установленный в значениеinline
, полиморфные адаптеры теперь не используются. Это положительно сказывается как на производительности построения запросов, так и на существенном упрощении внутреннего процесса визуализации запросов.Конкретная проблема заключалась в том, чтобы позволить
column_property()
ссылаться на объединенные классы наследования в скалярном подзапросе, что теперь работает настолько интуитивно, насколько это возможно.References: #8168
engine¶
Исправлено давнее состояние гонки в пуле соединений, которое могло возникать при использовании схем eventlet/gevent monkeypatching в сочетании с условиями eventlet/gevent
Timeout
, когда проверка пула соединений, прерванная из-за таймаута, не успевала очистить состояние отказа, что приводило к «утечке» базовой записи соединения, а иногда и самого соединения с базой данных, оставляя пул в неработоспособном состоянии с недоступными записями. Впервые эта проблема была выявлена и исправлена в SQLAlchemy 1.2 для #4225, однако режимы отказа, обнаруженные в этом исправлении, не учитывалиBaseException
, а неException
, что не позволяло перехватить эвентлет/гевентTimeout
. Кроме того, был выявлен и исправлен блок внутри начального соединения с пулом, в котором появился блокBaseException
-> «clean failed connect», учитывающий то же самое условие в этом месте. Большое спасибо пользователю Github @niklaus за упорную работу по выявлению и описанию этой сложной проблемы.This change is also backported to: 1.4.46
References: #8974
Исправлена проблема, при которой метод
Result.freeze()
не работал для текстового SQL, использующегоtext()
илиConnection.exec_driver_sql()
.This change is also backported to: 1.4.45
References: #8963
sql¶
Теперь в случае неудачи любой операции рендеринга «literal bindparam» выбрасывается информативное сообщение re-raise с указанием самого значения и используемого типа данных, чтобы помочь в отладке при рендеринге буквальных параметров в операторе.
This change is also backported to: 1.4.45
References: #8800
Исправлена проблема в лямбда-функции SQL, когда вычисляемый тип литерального значения не учитывал правила коэрцитивности типа «сравнивается с типом», что приводило к отсутствию информации о типе для SQL-выражений, таких как сравнение с элементами
JSON
и подобных.This change is also backported to: 1.4.46
References: #9029
Исправлен ряд проблем, связанных с расположением, а иногда и идентичностью отображаемых связанных параметров, например, для SQLite, asyncpg, MySQL, Oracle и других. В некоторых скомпилированных формах порядок параметров сохранялся некорректно, например, в функции PostgreSQL
regexp_replace()
, во «вложенной» конструкцииCTE
, впервые появившейся в #4123, а также в таблицах с выбором, сформированных методомFunctionElement.column_valued()
в Oracle.This change is also backported to: 1.4.45
References: #8827
Добавлена поддержка теста на то, что все методы компилятора
visit_xyz()
во всех реализацияхCompiler
в SQLAlchemy принимают параметр**kw
, так что все компиляторы принимают дополнительные аргументы в виде ключевых слов при любых обстоятельствах.References: #8988
Метод
SQLCompiler.construct_params()
, как и аксессорSQLCompiler.params
, теперь будет возвращать именно те параметры, которые соответствуют скомпилированному оператору, использовавшему для компиляции параметрrender_postcompile
. Ранее метод возвращал структуру параметров, которая сама по себе не соответствовала ни исходным, ни расширенным параметрам.Передача нового словаря параметров в
SQLCompiler.construct_params()
дляSQLCompiler
, построенного с помощьюrender_postcompile
, теперь запрещена; вместо этого для создания новой SQL-строки и набора параметров для альтернативного набора параметров добавлен новый методSQLCompiler.construct_expanded_state()
, который будет создавать новую расширенную форму для заданного набора параметров, используя контейнерExpandedState
, включающий новый SQL-оператор и новый словарь параметров, а также кортеж позиционных параметров.References: #6114
Для адаптации к сторонним диалектам с различными требованиями к экранированию символов в связанных параметрах, система, с помощью которой SQLAlchemy «экранирует» (т.е. заменяет другим символом) специальные символы в именах связанных параметров, была расширена для сторонних диалектов, используя словарь
SQLCompiler.bindname_escape_chars
, который может быть переопределен на уровне объявления класса для любого подклассаSQLCompiler
. В рамках этого изменения также добавлена точка"."
в качестве «экранированного» символа по умолчанию.References: #8994
typing¶
asyncio¶
Из
AsyncResult
удален нефункциональный методmerge()
. Этот метод никогда не работал и был включен вAsyncResult
по ошибке.This change is also backported to: 1.4.45
References: #8952
postgresql¶
Исправлена ошибка, при которой параметр PostgreSQL
Insert.on_conflict_do_update.constraint
принимал объектIndex
, но не разворачивал этот индекс в отдельные индексные выражения, а вместо этого выводил его имя в предложение ON CONFLICT ON CONSTRAINT, которое не принимается PostgreSQL; форма «constraint name» принимает только уникальные или исключающие имена ограничений. Параметр продолжает принимать индекс, но теперь разлагает его на составные выражения для рендеринга.This change is also backported to: 1.4.46
References: #9023
Внесена поправка в то, как диалект PostgreSQL учитывает типы столбцов при отражении столбцов из таблицы, для учета альтернативных бэкендов, которые могут возвращать NULL из функции PG
format_type()
.This change is also backported to: 1.4.45
References: #8748
Добавлена поддержка явного использования полнотекстовых функций PG с asyncpg и psycopg (только для SQLAlchemy 2.0) в части приведения типа
REGCONFIG
для первого аргумента, который ранее неверно приводился к VARCHAR, что приводило к сбоям в этих диалектах, полагающихся на явное приведение типов. Это включает поддержку диалектовto_tsvector
,to_tsquery
,plainto_tsquery
,phraseto_tsquery
,websearch_to_tsquery
,ts_headline
, каждый из которых в зависимости от количества переданных аргументов определяет, следует ли интерпретировать первый строковый аргумент как значение PostgreSQL «REGCONFIG»; если да, то аргумент типизируется с помощью нового объекта типаREGCONFIG
, который затем явно приводится в выражении SQL.References: #8977
Исправлена ошибка, при которой вновь переработанные типы диапазонов PostgreSQL, такие как
INT4RANGE
, не могли быть установлены в качестве имплантов пользовательского типаTypeDecorator
, вместо этого вызываяTypeError
.References: #9020
Теперь при сравнении с экземпляром другого класса
Range.__eq___()
будет возвращатьсяNotImplemented
, а не вызывать исключениеAttributeError
.References: #8984
sqlite¶
Добавлена поддержка бэкенда SQLite для отражения ключевых слов «DEFERRABLE» и «INITIALLY», которые могут присутствовать в конструкции внешнего ключа. Pull request любезно предоставлен Майклом Горвеном.
This change is also backported to: 1.4.45
References: #8903
Добавлена поддержка отражения ориентированных на выражения критериев WHERE, включенных в индексы на диалекте SQLite, аналогично тому, как это делается на диалекте PostgreSQL. Pull request любезно предоставлен Тобиасом Пфайффером.
This change is also backported to: 1.4.45
References: #8804
oracle¶
Исправлена проблема в компиляторе Oracle, когда синтаксис для
FunctionElement.column_valued()
был неверен, что приводило к появлению имениCOLUMN_VALUE
без корректной квалификации исходной таблицы.This change is also backported to: 1.4.45
References: #8945
tests¶
Исправлена проблема в файле tox.ini, когда изменения в серии tox 4.0 в формате «passenv» приводили к некорректной работе tox, в частности, вызывая ошибку начиная с tox 4.0.6.
This change is also backported to: 1.4.46
Добавлено новое правило исключения для сторонних диалектов
unusual_column_name_characters
, которое может быть «закрыто» для сторонних диалектов, не поддерживающих имена колонок с необычными символами, такими как точки, косые черты или знаки процента, даже если имя правильно заключено в кавычки.This change is also backported to: 1.4.46
References: #9002
2.0.0b4¶
Released: December 5, 2022orm¶
Добавлен новый параметр
mapped_column.use_existing_column
для реализации случая наследования одной таблицы, в котором используется схема, когда более одного подкласса указывают на один и тот же столбец в суперклассе. Ранее этот паттерн был возможен при использованииdeclared_attr()
в сочетании с размещением существующего столбца в.__table__
суперкласса, однако теперь он обновлен для работы сmapped_column()
, а также с типизацией pep-484, простым и лаконичным способом.См.также
References: #8822
Добавлена поддержка автоматического преобразования пользовательских типов, расширяющих базовый класс Python
enum.Enum
, в SQLAlchemyEnum
SQL-типы при использовании функции Annotated Declarative Table. Данная возможность стала возможной благодаря новым функциям поиска, добавленным в функцию ORM type map, и включает поддержку изменения аргументовEnum
, генерируемых по умолчанию, а также настройку конкретныхenum.Enum
типов внутри карты с определенными аргументами.References: #8859
Добавлен параметр
mapped_column.compare
в соответствующие конструкции атрибутов ORM, включаяmapped_column()
,relationship()
и т.д. для обеспечения параметра Python dataclassescompare
наfield()
при использовании возможности Декларативное отображение классов данных. Pull request любезно предоставлен Simon Schiele.References: #8905
Исправлена проблема, при которой использование неизвестного типа данных в аннотации
Mapped
для атрибута, основанного на столбце, приводило к молчаливому отказу в отображении атрибута, а не к сообщению об исключении; теперь выдается информативное сообщение об исключении.References: #8888
Исправлен ряд проблем, связанных с тем, что использование
Mapped
со словарными типами, такими какMapped[Dict[str, str] | None]
, некорректно интерпретировалось в декларативных ORM-маппингах. Исправлена поддержка корректной «деопционализации» этого типа, в том числе для поиска вtype_annotation_map
.References: #8777
Дополнительное повышение производительности SQL-запросов с поддержкой ORM, в частности, повышение производительности подсчета вызовов при построении ORM-запросов с использованием комбинаций
aliased()
сunion()
и подобных «составных» конструкций, а также прямое повышение производительности внутреннего методаcorresponding_column()
, который активно используется в ORM с помощью конструкций типаaliased()
и подобных.References: #8796
Исправлена ошибка в функции Декларативное отображение классов данных, когда использование в отображении простых полей класса данных с директивой
__allow_unmapped__
не создавало класс данных с правильным состоянием уровня класса для этих полей, копируя в класс необработанный объектField
после замены объектаField
значением по умолчанию на уровне класса.References: #8880
Исправлена ошибка, при которой при использовании параметра
Mapper.eager_defaults
происходила неудачная очистка сопоставленного класса, сопоставленного с подзапросом, например, при прямом сопоставлении или некоторых формах наследования конкретных таблиц.References: #8812
В версии 2.0.0b3 исправлена ошибка, связанная с #8759, когда при указании имени
Mapped
с помощью квалифицированного имени, напримерsqlalchemy.orm.Mapped
, Declarative не распознавал конструкцию как указывающую наMapped
.References: #8853
orm extensions¶
Добавлена поддержка функции расширения
association_proxy()
для участия в конфигурации Pythondataclasses
при использовании функции native dataclasses, описанной в Декларативное отображение классов данных. Включены аргументы на уровне атрибутов, в том числеassociation_proxy.init
иassociation_proxy.default_factory
.Документация по ассоциативным прокси также была обновлена для использования в примерах формы «Аннотированная декларативная таблица», включая аннотации типов, используемые для самого
AssocationProxy
.References: #8878
sql¶
Добавлен класс
ScalarValues
, который может использоваться в качестве элемента колонки, что позволяет использоватьValues
внутри предложенийIN
или в сочетании с агрегатами коллекцийANY
илиALL
. Новый класс генерируется с помощью методаValues.scalar_values()
. ЭкземплярValues
теперь принудительно преобразуется вScalarValues
при использовании в операцияхIN
илиNOT IN
.References: #6289
Исправлена критическая проблема с памятью при генерации ключей кэша, когда для очень больших и сложных ORM-выражений, использующих множество ORM-псевдонимов с подзапросами, генерация ключей кэша могла приводить к созданию слишком больших ключей, на порядки превышающих размер самого выражения. Большое спасибо Rollo Konig Brock за их очень терпеливую и длительную помощь в выявлении этой проблемы.
This change is also backported to: 1.4.44
References: #8790
Подход к параметру
numeric
pep-249 paramstyle был переписан и теперь полностью поддерживается, в том числе такими функциями, как «expanding IN» и «insertmanyvalues». Имена параметров также могут повторяться в исходной SQL-конструкции, что будет корректно представлено в числовом формате с использованием одного параметра. Введен дополнительный числовой стиль параметровnumeric_dollar
, который используется в диалекте asyncpg; этот стиль эквивалентенnumeric
, за исключением того, что числовые индикаторы обозначаются знаком доллара, а не двоеточием. Диалект asyncpg теперь использует парамстильnumeric_dollar
напрямую, а не компилирует сначала стильformat
.Стили параметров
numeric
иnumeric_dollar
предполагают, что целевой бэкенд способен принимать числовые параметры в любом порядке, и будет подставлять значения заданных параметров в утверждение на основе соответствия их позиции (на основе 1) числовому индикатору. Это нормальное поведение «числовых» стилей параметров, хотя было замечено, что в SQLite DBAPI реализован неиспользуемый «числовой» стиль, который не учитывает упорядочивание параметров.References: #8849
Скорректировано отображение
RETURNING
, в частности, при использованииInsert
, таким образом, что теперь столбцы отображаются с использованием той же логики, что и в конструкцииSelect
для генерации меток, которая включает в себя недвусмысленные метки, а также то, что SQL-функция, окружающая именованный столбец, будет обозначаться с использованием самого имени столбца. Это обеспечивает лучшую кросс-совместимость при выборе строк как из конструкцийSelect
, так и из операторов DML, использующихUpdateBase.returning()
. Для серии 1.4 также было сделано более узкое изменение, корректирующее только вопрос с метками функций.References: #8770
schema¶
Ужесточены правила добавления объектов
Column
к объектамTable
, что позволило перевести некоторые предыдущие предупреждения об устаревании в исключения и предотвратить некоторые предыдущие сценарии, которые приводили к появлению дублирующихся столбцов в таблицах, когдаTable.extend_existing
устанавливался вTrue
, как при программном построенииTable
, так и при операциях отражения.Сводная информация об этих изменениях приведена в разделе Более строгие правила замены столбцов в объектах Table с одинаковыми именами, ключами.
References: #8925
typing¶
Добавлен новый тип
SQLColumnExpression
, который может быть указан в пользовательском коде для представления любого выражения, ориентированного на столбец SQL, включая как те, которые основаны наColumnElement
, так и на ORMQueryableAttribute
. Этот тип является реальным классом, а не псевдонимом, поэтому может быть использован в качестве основы для других объектов. Также включен дополнительный подклассSQLORMExpression
, специфичный для ORM.References: #8847
Скорректировано внутреннее использование класса Python
enum.IntFlag
, который изменил свой поведенческий контракт в Python 3.11. Это не приводило к сбоям во время выполнения программы, но приводило к сбоям при наборе текста в Python 3.11.References: #8783
Расширения
sqlalchemy.ext.mutable
иsqlalchemy.ext.automap
теперь полностью типизированы в pep-484. Огромная благодарность Глебу Кисенкову за проделанную работу.Исправлена поддержка типизации для аргумента
relationship.secondary
, который также может принимать вызываемую переменную (лямбду), возвращающуюFromClause
.Улучшена типизация для
sessionmaker
иasync_sessionmaker
, так что по умолчанию их возвращаемое значение будет иметь типSession
илиAsyncSession
, без необходимости вводить это явно. Ранее Mypy не мог автоматически вывести эти типы возвращаемых значений из своей базы generic.В рамках этого изменения аргументы для
Session
,AsyncSession
,sessionmaker
иasync_sessionmaker
, помимо начального аргумента «bind», стали только ключевыми, что включает параметры, которые всегда документировались как ключевые, такие какSession.autoflush
,Session.class_
и т.д.Pull request courtesy Sam Bull.
References: #8842
Исправлена проблема, при которой передача вызываемой функции, возвращающей итерабель элементов столбцов, в
relationship.order_by
отмечалась как ошибка в программах проверки типов.References: #8776
postgresql¶
В дополнение к #8690 в объекты диапазонов, специфичные для PG, были добавлены новые методы сравнения
Range.adjacent_to()
,Range.difference()
,Range.union()
и т.д., что позволило привести их в соответствие со стандартными операторами, реализуемыми базовымAbstractRange.comparator_factory
.Кроме того, метод
__bool__()
класса был исправлен, чтобы соответствовать обычному поведению контейнеров Python, а также поведению других популярных драйверов PostgreSQL: теперь он определяет, является ли экземпляр диапазона не пустым, а не наоборот.Pull request courtesy Lele Gaifax.
References: #8765
Изменен paramstyle, используемый asyncpg, с
format
наnumeric_dollar
. Это имеет два основных преимущества, поскольку не требует дополнительной обработки оператора и позволяет использовать в операторах дублирующие параметры.References: #8926
Только для диалектов PostgreSQL и SQL Server компилятор настроен таким образом, что при выводе выражений столбцов в предложении RETURNING для элементов SQL-выражений, генерирующих метку, предлагается использовать метку «non anon», которая используется в операторах SELECT; основным примером является SQL-функция, которая может выдаваться как часть типа столбца, где имя метки по умолчанию должно совпадать с именем столбца. Это восстанавливает не вполне определенное поведение, которое изменилось в версии 1.4.21 из-за #6718, #6710. Диалект Oracle имеет другую реализацию RETURNING и не был затронут этой проблемой. В версии 2.0 внесены общие изменения для широкого расширения поддержки RETURNING в других бэкендах.
This change is also backported to: 1.4.44
References: #8770
Добавлено дополнительное определение типа для нового типа PostgreSQL
Range
, когда предыдущие случаи, позволявшие получать объекты psycopg2-native range напрямую в DBAPI без перехвата их SQLAlchemy, перестали работать, так как теперь у нас есть собственный объект value. ОбъектRange
был усовершенствован таким образом, что SQLAlchemy Core обнаруживает его в других неоднозначных ситуациях (например, при сравнении с датами) и применяет соответствующие обработчики связывания. Pull request любезно предоставлен Lele Gaifax.References: #8884
mssql¶
Исправлена регрессия, вызванная комбинацией команды #8177, повторно включающей setinputsizes для SQL server, если для оператора не используется fast_executemany + DBAPI executemany, и команды #6047, реализующей «insertmanyvalues», которая обходит DBAPI executemany вместо пользовательского DBAPI execute для операторов INSERT. При включении fast_executemany проверка некорректно не будет использовать setinputsizes для INSERT-оператора с несколькими параметрами, использующего «insertmanyvalues», так как будет ошибочно считать, что это вызов DBAPI executemany. В этом случае «регресс» будет заключаться в том, что формат оператора «insertmanyvalues», по-видимому, несколько более чувствителен к множественным строкам, в которых не используются одинаковые типы для каждой строки, поэтому в таком случае setinputsizes особенно необходим.
Исправление исправляет проверку fast_executemany таким образом, чтобы она отключала setinputsizes только в случае использования истинного DBAPI executemany.
References: #8917
oracle¶
tests¶
Исправлена проблема, при которой параметр
--disable-asyncio
в тестовом наборе не запускал тесты greenlet, а также не предотвращал использование «оберточного» greenlet для всего набора. Теперь этот параметр гарантирует, что в течение всего прогона не будет использоваться greenlet или asyncio.This change is also backported to: 1.4.44
References: #8793
2.0.0b3¶
Released: November 4, 2022orm¶
Исправлена проблема в объединенной ускоренной загрузке, когда при определенной комбинации внешней/внутренней объединенной ускоренной загрузки происходил сбой утверждения при ускоренной загрузке трех мэпперов, где средний мэппер был унаследованным мэппером подкласса.
This change is also backported to: 1.4.43
References: #8738
Исправлена ошибка, связанная с конструкциями
Select
, когда комбинацииSelect.select_from()
сSelect.join()
, а также при использованииSelect.join_from()
приводили к тому, что функцияwith_loader_criteria()
, а также критерии IN, необходимые для запросов наследования одной таблицы, не отображались в тех случаях, когда в предложении columns запроса не была явно указана левая сторона сущности JOIN. Теперь правильная сущность передается в объектJoin
, который генерируется внутренне, что позволяет корректно добавлять критерии к левосторонней сущности.This change is also backported to: 1.4.43
References: #8721
При использовании опции
with_loader_criteria()
в качестве опции загрузчика, добавленной к определенному «пути загрузчика», например, при использовании ее внутриLoad.options()
, теперь выдается информативное исключение. Такое использование не поддерживается, посколькуwith_loader_criteria()
предназначена только для использования в качестве опции загрузчика верхнего уровня. Ранее возникала внутренняя ошибка.This change is also backported to: 1.4.43
References: #8711
Улучшен «режим словаря» для
Session.get()
, благодаря чему имена синонимов, ссылающиеся на имена атрибутов первичного ключа, могут быть указаны в именованном словаре.This change is also backported to: 1.4.43
References: #8753
Исправлена проблема, при которой загрузка «selectin_polymorphic» для отображателей наследования работала некорректно, если параметр
Mapper.polymorphic_on
ссылался на SQL-выражение, которое не было непосредственно отображено на класс.This change is also backported to: 1.4.43
References: #8704
Исправлена проблема, когда при использовании объекта
Query
в качестве итератора базовый курсор DBAPI не закрывался, если в процессе итерации возникало определенное пользователем исключение, что приводило к закрытию итератора интерпретатором Python. При использованииQuery.yield_per()
для создания курсоров на стороне сервера это приводило к обычным для MySQL проблемам, связанным с рассинхронизацией курсоров на стороне сервера, и без прямого доступа к объектуResult
код конечного пользователя не мог получить доступ к курсору, чтобы закрыть его.Для решения проблемы внутри метода итератора применяется catch для
GeneratorExit
, который закроет объект result в тех случаях, когда итератор был прерван, и по определению будет закрыт интерпретатором Python.В рамках этого изменения, реализованного в серии 1.4, было обеспечено наличие методов
.close()
во всех реализацияхResult
, включаяScalarResult
,MappingResult
. В версии 2.0 это изменение также включает новые паттерны менеджера контекста для использования с классамиResult
.This change is also backported to: 1.4.43
References: #8710
orm declarative¶
В декларативных аннотациях ORM добавлена поддержка того, что имена классов, указанные для
relationship()
, а также имя самого символаMapped
могут отличаться от прямого имени класса, что позволяет поддерживать сценарии, в которыхMapped
импортируется какfrom sqlalchemy.orm import Mapped as M
, или когда смежные имена классов импортируются с альтернативным именем аналогичным образом. Кроме того, имя целевого класса, указанное в качестве ведущего аргумента дляrelationship()
, всегда будет заменять имя, указанное в левой аннотации, так что неимпортируемые имена, которые также не соответствуют имени класса, могут быть использованы в аннотациях.References: #8759
Улучшена поддержка устаревших связок версии 1.4, использующих аннотации, не включающие
Mapped[]
, за счет того, что атрибут__allow_unmapped__
может быть использован для пропуска таких аннотаций через Annotated Declarative без возникновения ошибки и без интерпретации в контексте времени выполнения ORM. Кроме того, улучшено сообщение об ошибке, выдаваемое при обнаружении этого условия, и добавлена дополнительная документация о том, как следует поступать в данной ситуации. К сожалению, предупреждение о миграции 1.4 WARN_SQLALCHEMY_20 не может обнаружить эту конкретную конфигурационную проблему во время выполнения при существующей архитектуре.References: #8692
Изменено фундаментальное поведение конфигурации
Mapper
, при котором объектыColumn
, явно присутствующие в словареMapper.properties
, либо непосредственно, либо заключенные в объект свойства отображения, теперь будут отображаться в том порядке, в котором они появляются в самом отображаемомTable
(или другом селекте) (при условии, что они действительно являются частью списка столбцов этой таблицы), тем самым сохраняя тот же порядок столбцов в отображаемом селекте, который установлен на отображаемом классе, а также то, что отображается в операторе ORM SELECT для этого мэппера. Ранее (где «ранее» означает начиная с версии 0.0.1) объектыColumn
в словареMapper.properties
всегда отображались первыми, опережая время отображения других столбцов в отображаемомTable
, что вызывало несоответствие в порядке присвоения атрибутов отображаемому классу и порядке их отображения в операторах.Наиболее заметные изменения происходят в том, как Declarative назначает объявленные столбцы в
Mapper
, в частности, как обрабатываются объектыColumn
(илиmapped_column()
), если их DDL-имя явно отличается от имени отображаемого атрибута, а также когда используются такие конструкции, какdeferred()
и т.д. В соответствии с новым поведением порядок следования столбцов в отображенномTable
будет соответствовать порядку, в котором атрибуты отображаются на класс, назначаются в самомMapper
и отображаются в операциях ORM, таких как операторы SELECT, независимо от того, какColumn
был сконфигурированMapper
.References: #8705
Исправлена проблема в новой функции сопоставления классов данных, когда столбец, объявленный в decalrative base / abstract base / mixin, при некоторых обстоятельствах просачивался в конструктор наследующего подкласса.
References: #8718
Исправлены проблемы в разрешителе декларативных типов (т.е. разрешающем объекты
ForwardRef
), когда типы, объявленные для колонок в одном конкретном исходном файле, вызывали ошибкуNameError
, если конечный сопоставленный класс находился в другом исходном файле. Теперь типы разрешаются в терминах модуля для каждого класса, в котором эти типы используются.References: #8742
engine¶
Для улучшения поддержки случаев итерации объектов
Result
иAsyncResult
, когда определяемые пользователем исключения могут прервать итерацию, оба объекта, а также такие варианты, какScalarResult
,MappingResult
,AsyncScalarResult
,AsyncMappingResult
, теперь поддерживают использование контекстного менеджера, в котором результат будет закрыт в конце блока контекстного менеджера.Кроме того, обеспечено наличие у всех перечисленных объектов
Result
методаResult.close()
, а также аксессоровResult.closed
, в том числе уScalarResult
иMappingResult
, которые ранее не имели метода.close()
.References: #8710
В событие
PoolEvents.reset()
добавлен новый параметрPoolEvents.reset.reset_state
, при этом предусмотрена логика обесценивания, которая позволит продолжать принимать хуки событий с предыдущим набором аргументов. Этот параметр указывает на различную информацию о состоянии, в котором происходит сброс, и используется для реализации пользовательских схем сброса с предоставлением полного контекста.В рамках этого изменения включено исправление, также перенесенное в 1.4, которое позволяет событию
PoolEvents.reset()
продолжать происходить при любых обстоятельствах, в том числе и когдаConnection
уже «сбросил» соединение.Эти два изменения позволяют реализовать пользовательские схемы сброса с использованием события
PoolEvents.reset()
вместо событияPoolEvents.checkin()
(которое продолжает работать как и раньше).References: #8717
Исправлена проблема, при которой крючок события
PoolEvents.reset()
вызывался не во всех случаях, когдаConnection
был закрыт и находился в процессе возврата своего DBAPI-соединения в пул соединений.Сценарий заключался в том, что хук
Connection
уже выполнил.rollback()
на своем DBAPI-соединении в процессе возврата соединения в пул, где он инструктировал пул соединений отказаться от выполнения собственного «сброса», чтобы сэкономить на дополнительном вызове метода. Однако это не позволяло использовать пользовательские схемы сброса пула в рамках данного хука, поскольку такие хуки по определению выполняют нечто большее, чем просто вызов.rollback()
, и должны вызываться при любых обстоятельствах. Это была регрессия, появившаяся в версии 1.4.В версии 1.4 функция
PoolEvents.checkin()
по-прежнему используется в качестве альтернативного крючка событий для пользовательских реализаций «сброса». В версии 2.0 появится улучшенная версияPoolEvents.reset()
, которая будет вызываться для дополнительных сценариев, таких как завершение asyncio-соединений, а также ей будет передаваться контекстная информация о сбросе, что позволит реализовать схемы «пользовательского сброса соединений», которые могут по-разному реагировать на различные сценарии сброса.This change is also backported to: 1.4.43
References: #8717
sql¶
Исправлена проблема, из-за которой конструкция
literal_column()
не могла корректно работать в контексте конструкцииSelect
, а также в других потенциальных местах генерации «анонимных меток», если литеральное выражение содержало символы, которые могли помешать строкам форматирования, например, открытую круглую скобку, что связано с особенностями реализации структуры «анонимная метка».This change is also backported to: 1.4.43
References: #8724
typing¶
Исправлены различные опечатки в пакетах engine и async engine.
postgresql¶
В новый объект данных
Range
добавлены новые методыRange.contains()
иRange.contained_by()
, которые повторяют поведение операторов PostgreSQL@>
и<@
, а также методов операторов SQLcomparator_factory.contains()
иcomparator_factory.contained_by()
. Pull request любезно предоставлен Леле Гайфаксом.References: #8706
Усовершенствован новый подход к объектам диапазона, описанный в Новая поддержка RANGE / MULTIRANGE и изменения для бэкендов PostgreSQL, с учетом специфических для драйвера объектов диапазона и мультидиапазона, что позволяет лучше использовать их как в устаревшем коде, так и при передаче результатов из необработанных наборов результатов SQL обратно в новые выражения диапазона или мультидиапазона.
References: #8690
mssql¶
Исправлена проблема с
Inspector.has_table()
, которая при использовании к временной таблице диалекта SQL Server приводила к ошибке на некоторых вариантах Azure из-за лишнего запроса к информационной схеме, который не поддерживается на этих версиях сервера. Pull request любезно предоставлен Майком Барри.This change is also backported to: 1.4.43
References: #8714
Исправлена проблема с
Inspector.has_table()
, которая при использовании против представления с диалектом SQL Server ошибочно возвращалаFalse
, что связано с регрессией в серии 1.4, удалившей поддержку этой функции на SQL Server. В серии 2.0, использующей другую архитектуру отражения, эта проблема отсутствует. Добавлена тестовая поддержка, чтобы убедиться, чтоhas_table()
продолжает работать в соответствии со спецификацией, касающейся представлений.This change is also backported to: 1.4.43
References: #8700
oracle¶
Исправлена проблема, при которой имена связанных параметров, в том числе автоматически получаемые из аналогичных по названию столбцов базы данных, содержащие символы, обычно требующие кавычек в Oracle, не экранировались при использовании «расширяющих параметров» в диалекте Oracle, что приводило к ошибкам выполнения. Обычное «кавычки» для связанных параметров, используемые диалектом Oracle, в архитектуре «расширяющих параметров» не применяются, поэтому вместо них используется экранирование для большого диапазона символов, теперь с использованием списка символов/эскейпов, специфичных для Oracle.
This change is also backported to: 1.4.43
References: #8708
Исправлена проблема, при которой представление
nls_session_parameters
, запрашиваемое при первом подключении для получения десятичного символа по умолчанию, могло быть недоступно в зависимости от режимов подключения Oracle, что приводило к возникновению ошибки. Подход к определению десятичного символа был упрощен и теперь проверяется непосредственно десятичное значение, а не чтение системных представлений, что работает на любом бэкенде/драйвере.This change is also backported to: 1.4.43
References: #8744
2.0.0b2¶
Released: October 20, 2022orm¶
Убрано предупреждение, выдаваемое при использовании ORM-совместимых update/delete относительно оценки столбцов по имени, впервые добавленное в #4073; это предупреждение фактически закрывает сценарий, в котором в противном случае может быть выдано неверное значение Python для атрибута, сопоставленного ORM, в зависимости от того, каким является реальный столбец, поэтому этот устаревший случай удален. В версии 2.0 для обновления/удаления с поддержкой ORM используется значение «auto» для «synchronize_session», которое должно автоматически выполнять правильные действия для любого заданного выражения UPDATE.
References: #8656
orm declarative¶
Добавлена поддержка отображения классов, которые также являются подклассами
Generic
, для указания их в виде объектаGenericAlias
(например,MyClass[str]
) в операторах и вызовахinspect()
.References: #8665
Класс
DeclarativeBase
улучшен таким образом, что в сочетании с другими миксинами, напримерMappedAsDataclass
, порядок следования классов может быть любым.References: #8665
Исправлена ошибка в новых типизированных декларативных отображениях ORM, когда в аннотации типа для отношения «многие-к-одному» не была реализована возможность использования
Optional[MyClass]
или аналогичных форм, таких какMyClass | None
, что приводило к ошибкам. Документация для этого случая использования также была добавлена в документацию по конфигурации отношений.References: #8668
Исправлена проблема с новой функцией отображения классов данных, когда аргументы, передаваемые в API классов данных, иногда могли быть неправильно упорядочены при работе с миксинами, переопределяющими объявления
mapped_column()
, что приводило к проблемам с инициализаторами.References: #8688
sql¶
Исправлена ошибка в новой функции «insertmanyvalues», когда INSERT, включающий в себя подзапрос с
bindparam()
внутри, не мог корректно отображаться в формате «insertmanyvalues». В наибольшей степени это затрагивало psycopg2, так как «insertmanyvalues» используется в этом драйвере безусловно.References: #8639
typing¶
Исправлена проблема, при которой в строгом режиме pylance выдавалось сообщение «instance variable overrides class variable» при использовании метода для определения
__tablename__
,__mapper_args__
или__table_args__
.References: #8645
Исправлена проблема типизации, при которой строгий режим pylance сообщал о «частично неизвестном» типе данных для конструкции
mapped_column()
.References: #8644
mssql¶
Исправлена регрессия, вызванная изменением SQL Server pyodbc #8177, где теперь по умолчанию используется
setinputsizes()
; для VARCHAR это не удается, если размер символа превышает 4000 (или 2000, в зависимости от данных) символов, поскольку входящий тип данных - NVARCHAR, который имеет ограничение в 4000 символов, несмотря на то, что VARCHAR может работать с неограниченным количеством символов. Дополнительная информация о типизации, специфичная для pyodbc, теперь передается вsetinputsizes()
, если размер типа данных > 2000 символов. Это изменение распространяется и на типJSON
, который также был подвержен этой проблеме при сериализации больших JSON-файлов.References: #8661
Конструкция
Sequence
возвращается к поведению DDL до версии 1.4, когда созданиеSequence
без дополнительных аргументов приводит к появлению простой инструкцииCREATE SEQUENCE
без дополнительных параметров для «начального значения». В любом случае, для большинства бэкендов именно так все и происходило; как бы то ни было, для MS SQL Server значение по умолчанию для этой базы данных равно-2**63
; чтобы предотвратить действие этого в общем-то непрактичного значения по умолчанию на SQL Server, необходимо указать параметрSequence.start
. Поскольку использованиеSequence
необычно для SQL Server, который в течение многих лет стандартизировался наIDENTITY
, можно надеяться, что это изменение окажет минимальное влияние.References: #7211
2.0.0b1¶
Released: October 13, 2022general¶
В результате миграции кодовой базы были удалены все модели поведения и архитектуры, существовавшие до версии 2.0, которые ранее были отмечены как устаревшие и подлежащие удалению в версии 2.0, включая, но не ограничиваясь ими:
удален весь код Python 2, минимальной версией теперь является Python 3.7
Engine
иConnection
теперь используют новый стиль работы 2.0, который включает в себя «autobegin», удален автокоммит на уровне библиотеки, удалены субтранзакции и «разветвленные» соединенияОбъекты-результаты используют поведение в стиле 2.0;
Row
является полностью именованным кортежем без поведения «отображения», для поведения «отображения» используйтеRowMapping
Из SQLAlchemy удалена вся архитектура кодирования/декодирования Unicode. Все современные реализации DBAPI поддерживают Unicode прозрачно благодаря Python 3, поэтому функция
convert_unicode
, а также связанные с ней механизмы поиска байтовых строк в DBAPIcursor.description
и т.д. были удалены.Атрибут
.bind
и параметрMetaData
,Table
, а также все элементы DDL/DML/DQL, которые ранее могли ссылаться на «связанный движок»Автономная функция
sqlalchemy.orm.mapper()
удалена, все классическое отображение должно осуществляться через методregistry.map_imperatively()
изregistry
.Метод
Query.join()
больше не принимает строки для имен отношений; давно задокументированный подход использованияClass.attrname
для целей соединения теперь является стандартным.Query.join()
больше не принимает аргументы «aliased» и «from_joinpoint»Query.join()
больше не принимает цепочки из нескольких целей присоединения в одном вызове метода.Query.from_self()
,Query.select_entity_from()
иQuery.with_polymorphic()
удалены.Параметр
relationship.cascade_backrefs
теперь должен оставаться по умолчаниюFalse
; каскадsave-update
больше не каскадирует по обратной ссылке.параметр
Session.future
всегда должен быть установлен в значениеTrue
. Шаблоны транзакций в стиле 2.0 дляSession
теперь действуют всегда.Опции загрузчика больше не принимают строки для имен атрибутов. Давно документированный подход использования
Class.attrname
для целей опций загрузчика теперь является стандартным.Устаревшие формы
select()
удалены, включаяselect([cols])
, «whereclause» и параметры ключевых словsome_table.select()
.Устранены устаревшие методы «in-place mutator» на
Select
, такие какappend_whereclause()
,append_order_by()
и т.д.Удален очень старый модуль «dbapi_proxy», который в самых ранних версиях SQLAlchemy использовался для создания прозрачного пула соединений над сырым DBAPI-соединением.
References: #7257
Метод
Query.instances()
является устаревшим. Поведенческий контракт этого метода, заключающийся в том, что он может итерировать объекты через произвольные наборы результатов, давно устарел и больше не тестируется. Произвольные операторы могут возвращать объекты, используя такие конструкции, как :meth`.Select.from_statement` oraliased()
.
platform¶
Расширения SQLAlchemy на языке C были заменены новыми реализациями, написанными на языке Cython. Как и для предыдущих расширений на языке C, на pypi доступны предварительно собранные файлы wheel для широкого спектра платформ, так что сборка для распространенных платформ не представляет проблемы. Для пользовательских сборок
python setup.py build_ext
работает как и раньше, требуя лишь дополнительной установки Cython.pyproject.toml
теперь также является частью исходного кода, что позволит установить правильные зависимости сборки при использовании pip.References: #7256
Сборка и установка исходных текстов SQLAlchemy теперь включает файл
pyproject.toml
для полной поддержки PEP 517.References: #7311
orm¶
Во все включенные диалекты, поддерживающие RETURNING, добавлена новая функция «insertmanyvalues». Это обобщение функции «fast executemany», впервые представленной для драйвера psycopg2 в версии 1.4 ORM Пакетные вставки с psycopg2 теперь в большинстве случаев выполняют пакетные операции с RETURNING, которая позволяет ORM пакетно объединять операторы INSERT в гораздо более эффективную структуру SQL, сохраняя при этом возможность получать новые значения первичного ключа и значения по умолчанию SQL с помощью RETURNING.
Теперь эта возможность распространяется на многие диалекты, поддерживающие конструкцию RETURNING вместе с несколькими VALUES для INSERT, включая все драйверы PostgreSQL, SQLite, MariaDB, MS SQL Server. Отдельно такую же возможность получает диалект Oracle, используя собственные функции cx_Oracle или OracleDB.
References: #6047
Добавлен новый параметр
AttributeEvents.include_key
, который будет включать в себя ключ словаря или списка для таких операций, как__setitem__()
(например,obj[key] = value
) и__delitem__()
(например,del obj[key]
), используя новый параметр-ключ «key» или «keys», в зависимости от события, например,AttributeEvents.append.key
,AttributeEvents.bulk_replace.keys
. Это позволяет обработчикам событий учитывать ключ, который был передан операции, и особенно важно для словарных операций, работающих сMappedCollection
.References: #8375
Добавлен новый параметр
Operators.op.python_impl
, доступный изOperators.op()
, а также при непосредственном использовании конструктораcustom_op
, который позволяет предоставлять вместе с пользовательским SQL-оператором функцию оценки на языке Python. Эта оценочная функция становится реализацией, используемой при использовании объекта operator, когда в качестве операндов с обеих сторон используются обычные объекты Python, и, в частности, совместима с опциейsynchronize_session='evaluate'
, используемой с Операции INSERT, UPDATE и DELETE с поддержкой ORM.References: #3162
В
Session
(и, соответственно, вAsyncSession
) появилась новая функциональность отслеживания состояния, которая позволяет проактивно отлавливать любые неожиданные изменения состояния, происходящие по мере выполнения того или иного транзакционного метода. Это позволит в ситуациях, когдаSession
используется небезопасным для потоков образом, когда крючки событий и т.п. могут вызывать неожиданные методы внутри операций, а также в других ситуациях параллелизма, таких как asyncio или gevent, выдавать информационное сообщение при первом незаконном доступе, а не проходить молча, приводя к вторичным сбоям из-за того, чтоSession
находится в недопустимом состоянии.См.также
Проактивно поднимать сессию при обнаружении незаконного одновременного или реентерабельного доступа
References: #7433
Конструкция отображения
composite()
теперь поддерживает автоматическое разрешение значений при использовании с Pythondataclass
; метод__composite_values__()
больше не нужно реализовывать, так как этот метод получается в результате проверки класса данных.Кроме того, классы, отображаемые с помощью
composite
, теперь поддерживают операции упорядоченного сравнения, например<
,>=
и т.д.Примеры смотрите в новой документации по адресу Типы составных колонн.
В опции загрузчика
selectinload()
иimmediateload()
добавлена экспериментальная возможностьselectinload.recursion_depth
/immediateload.recursion_depth
, которая позволяет одной опции загрузчика автоматически осуществлять рекурсию по самореферентным связям. Устанавливается в целое число, указывающее глубину, а также может быть установлено в -1, чтобы указать на продолжение загрузки до тех пор, пока не будет найдено больше ни одного уровня в глубину. Значительные внутренние изменения вselectinload()
иimmediateload()
позволяют этой возможности работать, продолжая корректно использовать кэш компиляции, а также не использовать произвольную рекурсию, так что поддерживается любой уровень глубины (хотя при этом будет выдаваться такое количество запросов). Это может быть полезно для самореферентных структур, которые должны загружаться полностью с нетерпением, например, при использовании asyncio.Предупреждение выдается также при соединении опций загрузчика с произвольной длиной (то есть без использования новой опции
recursion_depth
), когда в загрузке связанных объектов обнаруживается чрезмерная глубина рекурсии. Такая операция продолжает использовать огромные объемы памяти и работает крайне плохо; для защиты кэша от переполнения произвольными утверждениями при обнаружении этого условия кэш отключается.References: #8126
Добавлен новый параметр
Session.autobegin
, который при установке значенияFalse
не позволит методуSession
начать транзакцию неявно. Для продолжения операций необходимо сначала явно вызвать методSession.begin()
, иначе будет выдана ошибка, если какая-либо операция в противном случае началась бы автоматически. Эта опция может быть использована для создания «безопасного»Session
, который не будет неявно начинать новые транзакции.В рамках этого изменения также добавлена новая переменная состояния
origin
, которая может быть полезна для кода обработки событий, чтобы знать о происхождении конкретногоSessionTransaction
.References: #6928
Декларативным миксинам, использующим объекты
Column
, содержащие ссылкиForeignKey
, больше не нужно использоватьdeclared_attr()
для достижения такого отображения; объектForeignKey
копируется вместе с самимColumn
при применении колонки к объявленному отображению.В опцию загрузчика
load_only()
добавлен параметрload_only.raiseload
, чтобы выгружаемые атрибуты могли иметь поведение «raise», а не ленивую загрузку. Ранее не было возможности сделать это с помощью параметраload_only()
напрямую.Для более удобного использования явной типизации имена некоторых ORM-конструкций, которые обычно строятся внутри, но, тем не менее, иногда проявляются при обмене сообщениями, а также при типизации, были изменены на более лаконичные имена, которые также соответствуют имени функции-конструктора (с другим регистром), во всех случаях сохраняя псевдонимы на старые имена на обозримое будущее:
RelationshipProperty
становится псевдонимом для основного имениRelationship
, которое строится, как всегда, из функцииrelationship()
SynonymProperty
становится псевдонимом для основного имениSynonym
, построенного, как всегда, на основе функцииsynonym()
CompositeProperty
становится псевдонимом для основного имениComposite
, построенного, как всегда, на основе функцииcomposite()
Для согласованности с известной концепцией ORM
Mapped
названия коллекций, ориентированных на словари,attribute_mapped_collection()
,column_mapped_collection()
иMappedCollection
, изменены наattribute_keyed_dict()
,column_keyed_dict()
иKeyFuncDict
, причем словосочетание «dict» используется для того, чтобы свести к минимуму путаницу с термином «mapped». Старые имена останутся на неопределенный срок, и их удаление не планируется.References: #8608
Теперь все объекты
Result
будут последовательно вызыватьResourceClosedError
, если они используются после жесткого закрытия, которое включает в себя «жесткое закрытие», возникающее после вызова методов «одной строки или значения», таких какResult.first()
иResult.scalar()
. Такое поведение уже было характерно для наиболее распространенного класса объектов результатов, возвращаемых при выполнении операторов Core, т.е. для объектов, основанных наCursorResult
, поэтому такое поведение не является новым. Однако это изменение было расширено для того, чтобы должным образом учесть «фильтрацию» ORM-объектов, возвращаемых при использовании ORM-запросов в стиле 2.0, которые ранее вели себя в стиле «мягкого закрытия», возвращая пустые результаты, или вообще не «мягко закрывались» и продолжали выдавать результаты из базового курсора.В рамках этого изменения в базовый класс
Result
был добавленResult.close()
и реализован для реализаций фильтрованных результатов, используемых ORM, чтобы можно было вызвать методCursorResult.close()
на базовомCursorResult
, когда используется опция выполненияyield_per
, чтобы закрыть курсор на стороне сервера до того, как будут извлечены оставшиеся результаты ORM. Эта возможность уже была доступна для наборов результатов Core, но данное изменение делает ее доступной и для результатов ORM в стиле 2.0.This change is also backported to: 1.4.27
References: #7274
Исправлена проблема, при которой метод
registry.map_declaratively()
возвращал внутренний объект «mapper config», а не объектMapper
, как указано в документации к API.Исправлена регрессия производительности, проявившаяся как минимум в версии 1.3, если не раньше (спустя некоторое время после 1.0), когда при загрузке отложенных колонок, явно отображенных с помощью
defer()
, в отличие от не отложенных колонок, срок действия которых истек, из объединенного подкласса наследования не использовался «оптимизированный» запрос, который запрашивал только непосредственную таблицу, содержащую невыгруженные колонки, а выполнялся полный ORM-запрос, создающий JOIN для всех базовых таблиц, что не требуется при загрузке колонок только из подкласса.References: #7463
Внутренние компоненты объекта
Load
и связанных с ним шаблонов стратегий загрузчика были в основном переписаны, чтобы воспользоваться тем фактом, что теперь поддерживаются только пути, связанные с атрибутами, а не строки. Эта переработка позволит в дальнейшем более просто решать новые задачи и тонкие проблемы в системе стратегий загрузчика.References: #6986
Внесено улучшение в набор опций стратегии «отложенная» / «load_only», при котором, если определенный объект загружается из двух различных логических путей в рамках одного запроса, атрибуты, которые были настроены хотя бы в одном из вариантов на заполнение, будут заполнены во всех случаях, даже если в других путях загрузки этого же объекта данная опция не была установлена. ранее это было основано на случайности того, какой «путь» обратился к объекту первым.
References: #8166
Исправлена проблема, связанная с UPDATE с поддержкой ORM, когда оператор создается в подклассе с объединенным наследованием и обновляет только локальные столбцы таблицы, когда стратегия синхронизации «fetch» не приводила к корректной формуле RETURNING для баз данных, использующих RETURNING для синхронизации fetch. Также скорректирована стратегия, используемая для RETURNING в операторах UPDATE FROM и DELETE FROM.
References: #8344
Удалены неиспользуемые аргументы
**kw
изbegin
иbegin_nested
. Эти kw не используются и, по-видимому, были добавлены в API ошибочно.References: #7703
Изменен метод доступа к атрибутам
attribute_mapped_collection()
иcolumn_mapped_collection()
(теперь они называютсяattribute_keyed_dict()
иcolumn_keyed_dict()
), используемый при заполнении словаря, для подтверждения того, что значение данных в объекте, используемом в качестве ключа словаря, действительно присутствует, а не используется «None» из-за того, что атрибут никогда не был назначен. Это используется для предотвращения ошибочного использования None в качестве ключа при назначении через обратную ссылку, когда атрибут «key» объекту еще не назначен.Поскольку возникающая здесь ошибка является преходящим состоянием, которое обычно не сохраняется в базе данных, и легко возникает в конструкторе класса на основе порядка присваивания параметров, вполне возможно, что во многих приложениях такое поведение уже присутствует, и оно молчаливо передается. Для того чтобы учесть особенности приложений, в которых теперь возникает такая ошибка, к параметрам
attribute_keyed_dict()
иcolumn_keyed_dict()
добавлен новый параметрattribute_keyed_dict.ignore_unpopulated_attribute
, который вместо этого заставляет пропустить ошибочное присваивание обратной ссылки.References: #8372
Добавлен новый параметр
AbstractConcreteBase.strict_attrs
в декларативный класс миксинаAbstractConcreteBase
. В результате использования этого параметра область действия атрибутов подклассов корректно ограничивается подклассом, в котором объявлен каждый атрибут, а не как раньше, когда все атрибуты всей иерархии применяются к базовому «абстрактному» классу. В результате получается более чистое и корректное отображение, в котором подклассы больше не имеют неиспользуемых атрибутов, относящихся только к классам-братьям. По умолчанию для этого параметра установлено значение False, которое оставляет прежнее поведение без изменений; это сделано для поддержки существующего кода, который явно использует эти атрибуты в запросах. Для перехода к новому подходу следует по мере необходимости применять явные атрибуты к абстрактному базовому классу.References: #8403
Поведение
defer()
в отношении столбцов первичного ключа и «полиморфного дискриминатора» изменено таким образом, что эти столбцы больше не могут быть отложены ни явно, ни при использовании подстановочного символа, такого какdefer('*')
. Ранее отсрочка с использованием подстановочного знака не загружала PK/полиморфные столбцы, что приводило к ошибкам во всех случаях, поскольку ORM использует эти столбцы для создания идентификаторов объектов. Поведение явной отсрочки столбцов первичного ключа не изменилось, так как эти отсрочки уже игнорировались неявно.References: #7495
Исправлена ошибка в поведении параметра
Mapper.eager_defaults
, в результате которой выражения SQL по умолчанию или onupdate на стороне клиента, находящиеся только в определении таблицы, будут вызывать операцию выборки с использованием RETURNING или SELECT, когда ORM выдает INSERT или UPDATE для строки. Ранее только значения по умолчанию на стороне сервера, установленные как часть DDL таблицы, и/или выражения onupdate на стороне сервера вызывали такую выборку, даже если выражения SQL на стороне клиента были включены при выводе выборки.References: #7438
engine¶
Событие
DialectEvents.handle_error()
теперь перенесено в наборDialectEvents
из набораEngineEvents
и теперь участвует в событии «pre ping» пула соединений для тех диалектов, которые используют коды разъединения для определения наличия базы данных. Это позволяет конечному пользователю изменять состояние «pre ping». Обратите внимание, что это не относится к диалектам, содержащим собственный метод «ping», например, к psycopg2 или большинству диалектов MySQL.References: #5648
Крючки событий
ConnectionEvents.set_connection_execution_options()
иConnectionEvents.set_engine_execution_options()
теперь позволяют модифицировать заданный словарь опций на месте, при этом новое содержимое будет получено в качестве конечных опций выполнения, с которыми нужно будет работать. Ранее модификация словаря на месте не поддерживалась.Обобщен параметр
create_engine.isolation_level
на базовый диалект, чтобы он больше не зависел от наличия отдельных диалектов. Этот параметр устанавливает значение «уровня изоляции» для всех новых соединений с базой данных сразу после их создания пулом соединений, после чего это значение остается установленным и не сбрасывается при каждой проверке.Параметр
create_engine.isolation_level
по своей функциональности эквивалентен использованию параметраEngine.execution_options.isolation_level
черезEngine.execution_options()
для настройки всего движка. Разница заключается в том, что в первом случае уровень изоляции назначается один раз при создании соединения, а во втором - устанавливается и сбрасывается при каждой проверке соединения.References: #6342
Небольшие изменения в API, касающиеся движков и диалектов:
Методам
Dialect.set_isolation_level()
,Dialect.get_isolation_level()
, :meth: dialect всегда будет передаваться необработанное соединение DBAPIКлассы
Connection
иEngine
больше не имеют общего базового суперклассаConnectable
, который был удален.Добавлен новый интерфейсный класс
PoolProxiedConnection
- это публичный интерфейс для знакомого класса_ConnectionFairy
, который, тем не менее, является частным классом.
References: #7122
Исправлена регрессия, при которой метод
CursorResult.fetchmany()
не приводил к автозакрытию курсора на стороне сервера (т.е. при использованииstream_results
илиyield_per
, ориентированных на Core или ORM), когда результаты были полностью исчерпаны.This change is also backported to: 1.4.27
References: #7274
В будущих
Engine
исправлена проблема, когда вызовEngine.begin()
и вход в контекстный менеджер не закрывал соединение, если сама операция BEGIN по какой-то причине не выполнялась, например, обработчик события вызывал исключение; этот вариант использования не удалось протестировать для будущей версии движка. Обратите внимание, что «будущие» контекстные менеджеры, обрабатывающие блокиbegin()
в Core и ORM, не выполняют операцию «BEGIN» до тех пор, пока не будут введены контекстные менеджеры. Это отличается от старой версии, в которой операция «BEGIN» выполняется заранее.This change is also backported to: 1.4.27
References: #7272
Теперь
QueuePool
игнорируетmax_overflow
приpool_size=0
, делая пул неограниченным во всех случаях.References: #8523
Для повышения безопасности объект
URL
теперь по умолчанию использует обфускацию пароля при вызовеstr(url)
. Для структуризации URL с паролем в открытом виде можно использоватьURL.render_as_string()
, передавая параметрURL.render_as_string.hide_password
в видеFalse
. Спасибо нашим соавторам за этот pull request.References: #8567
Метод
Inspector.has_table()
теперь будет последовательно проверять наличие представлений с заданным именем, а также таблиц. Ранее такое поведение зависело от диалекта: PostgreSQL, MySQL/MariaDB и SQLite поддерживали его, а Oracle и SQL Server не поддерживали. Диалекты сторонних разработчиков также должны стремиться к тому, чтобы их методInspector.has_table()
выполнял поиск представлений, а также таблиц для заданного имени.References: #7161
Исправлена проблема в методе
Result.columns()
, когда вызовResult.columns()
с единственным индексом в некоторых случаях, особенно в случаях с объектами результатов ORM, мог привести к тому, чтоResult
выдавал скалярные объекты, а не объектыRow
, как если бы был вызван методResult.scalars()
. В SQLAlchemy 1.4 при таком сценарии выдается предупреждение о том, что поведение изменится в SQLAlchemy 2.0.References: #7953
Передача объекта
DefaultGenerator
, такого какSequence
, в методConnection.execute()
является устаревшей, поскольку этот метод типизирован как возвращающий объектCursorResult
, а не простое скалярное значение. Вместо него следует использовать методConnection.scalar()
, который был переработан с новыми внутренними кодовыми путями, чтобы можно было вызывать SELECT для объектов генерации по умолчанию, не проходя через методConnection.execute()
.Из
create_engine()
удален ранее устаревший параметрcase_sensitive
, который влиял только на поиск строковых имен столбцов в строках набора результатов только для Core; на поведение ORM он не влиял. Эффективное поведение параметраcase_sensitive
, на который ссылается , остается на уровне значения по умолчаниюTrue
, что означает, что имена строк, найденные вrow._mapping
, будут соответствовать регистру, как и любое другое отображение Python.Заметим, что параметр
case_sensitive
никак не связан с общей темой контроля чувствительности к регистру, кавычек и «нормализации имен» (т.е. преобразования для баз данных, считающих все слова в верхнем регистре нечувствительными к регистру) для имен идентификаторов DDL, которая остается нормальной основной особенностью SQLAlchemy.Удален устаревший и устаревший пакет
sqlalchemy.databases
. Вместо него следует использоватьsqlalchemy.dialects
.References: #7258
Параметр
create_engine.implicit_returning
устарел только для функцииcreate_engine()
; параметр остается доступным для объектаTable
. Этот параметр изначально предназначался для включения функции «неявного возврата» в SQLAlchemy, когда она только разрабатывалась, и не был включен по умолчанию. При современном использовании нет причин отключать этот параметр, и было замечено, что он вызывает путаницу, поскольку снижает производительность и затрудняет получение ORM недавно вставленных серверных значений по умолчанию. Параметр остается доступным наTable
специально для тех случаев на уровне базы данных, которые делают RETURNING невыполнимым, единственным примером в настоящее время является ограничение SQL Server на то, что INSERT RETURNING не может быть использован в таблице, на которую установлены триггеры INSERT.References: #6962
sql¶
В дополнение к существующим операторам композиции LIKE
ColumnOperators.contains()
,ColumnOperators.startswith()
и т.д. добавлены давно востребованные операторы строкColumnOperators.icontains()
,ColumnOperators.istartswith()
,ColumnOperators.iendswith()
, которые создают композиции LIKE с учетом регистра (с использованием функции ILIKE в PostgreSQL и функции LOWER() во всех остальных бэкендах). Огромная благодарность Матиасу Мартинесу Ребори за кропотливую и полную работу по реализации этих новых методов.References: #3482
Добавлен новый синтаксис к коллекции
FromClause.c
на всех объектахFromClause
, позволяющий передавать кортежи ключей в__getitem__()
, а также поддержка конструкцииselect()
для непосредственной работы с полученной кортежеподобной коллекцией, что позволяет использовать синтаксисselect(table.c['a', 'b', 'c'])
. Возвращаемая подколлекция сама являетсяColumnCollection
, которая также непосредственно потребляетсяselect()
и другими подобными средствами.См.также
References: #8285
Добавлен новый бэкенд-агностический тип данных
Uuid
, обобщенный из диалектов PostgreSQL и ставший основным типом, а также перенесенныйUUID
из диалекта PostgreSQL. Тип данных SQL ServerUNIQUEIDENTIFIER
также стал типом данных, работающим с UUID. Спасибо Тревору Гроссу за помощь в этом вопросе.References: #7212
В пространство имен базового модуля
sqlalchemy.
добавлены типы данныхDouble
,DOUBLE
,DOUBLE_PRECISION
для явного использования двойной/двухкратной точности, а также общие типы данных «double». ИспользуйтеDouble
для общей поддержки, которая будет преобразовываться в DOUBLE/DOUBLE PRECISION/FLOAT по мере необходимости для различных бэкендов.References: #5465
Изменена механика компиляции конструкции
Insert
таким образом, что значение столбца «autoincrement primary key» будет получено черезcursor.lastrowid
или RETURNING, даже если оно присутствует в наборе параметров или в методеInsert.values()
в виде простого связанного значения, для однорядных операторов INSERT на определенных бэкендах, которые, как известно, генерируют автоинкрементные значения даже при явном передаче NULL. Это восстанавливает поведение, которое было в серии 1.3 как для случая использования отдельного набора параметров, так и дляInsert.values()
. В версии 1.4 поведение набора параметров непреднамеренно изменилось и перестало выполняться, но методInsert.values()
по-прежнему получал автоинкрементные значения вплоть до версии 1.4.21, в которой метод #6770 снова непреднамеренно изменил поведение, поскольку этот вариант использования никогда не рассматривался.Теперь поведение определено как «рабочее» для случая, когда такие базы данных, как SQLite, MySQL и MariaDB, будут игнорировать явное значение первичного ключа NULL и, тем не менее, вызывать генератор автоинкремента.
References: #7998
Добавлено модифицированное отображение ISO-8601 (т.е. ISO-8601 с T, преобразованным в пробел) при использовании
literal_binds
с SQL-компиляторами, предоставляемыми диалектами PostgreSQL, MySQL, MariaDB, MSSQL, Oracle. Для Oracle формат ISO оборачивается внутрь соответствующего вызова функции TO_DATE(). Ранее для компиляции в зависимости от диалекта этот рендеринг не был реализован.См.также
Типы данных DATE, TIME, DATETIME теперь поддерживают литеральный рендеринг на всех бэкендах
References: #5052
В
HasCTE.add_cte()
добавлен новый параметрHasCTE.add_cte.nest_here
, который будет «вложен» в данныйCTE
на уровне родительского оператора. Этот параметр эквивалентен использованию параметраHasCTE.cte.nesting
, но в некоторых сценариях может быть более интуитивным, поскольку позволяет задавать атрибут вложенности одновременно с явным уровнем CTE.Метод
HasCTE.add_cte()
также принимает несколько объектов CTE.References: #7759
Клаузы FROM, установленные в конструкции
select()
при использовании методаSelect.select_from()
, теперь будут отображаться первыми в клаузе FROM рендерируемого SELECT, что позволяет сохранить порядок клауз, переданный в методSelect.select_from()
, и не зависеть от наличия этих клауз в других частях запроса. Если другие элементыSelect
также генерируют предложения FROM, например, предложение columns или предложение WHERE, то они будут отображаться после предложений, переданныхSelect.select_from()
, если они не были явно переданы вSelect.select_from()
. Это улучшение полезно в тех случаях, когда конкретная база данных формирует желаемый план запроса на основе определенного порядка следования предложений FROM и позволяет полностью контролировать порядок следования предложений FROM.References: #7888
Параметр
Enum.length
, задающий длину столбцаVARCHAR
для неродных типов перечислений, теперь безоговорочно используется при создании DDL для типа данныхVARCHAR
, в том числе и при установке параметраEnum.native_enum
в значениеTrue
для целевых бэкендов, продолжающих использоватьVARCHAR
. Ранее в этом случае параметр ошибочно игнорировался. Предупреждение, выдававшееся ранее для этого случая, теперь удалено.References: #7791
Определение типа на месте для целых чисел Python, как это происходит с выражением
literal(25)
, теперь также будет применять адаптацию на основе значений для больших целых чисел Python, где определяемый тип данных будетBigInteger
, а неInteger
. Это позволяет использовать такие диалекты, как asyncpg, который как передает драйверу неявную информацию о типе, так и чувствителен к числовым масштабам.References: #7909
Добавлены параметры
if_exists
иif_not_exists
для всех конструкций «Create» / «Drop», включаяCreateSequence
,DropSequence
,CreateIndex
,DropIndex
и т.д., позволяющие выводить общие фразы «IF EXISTS» / «IF NOT EXISTS» в DDL. Pull request любезно предоставлен Jesse Bakker.References: #7354
Улучшено построение бинарных выражений SQL, что позволяет использовать очень длинные выражения против одного и того же ассоциативного оператора без специальных действий, чтобы избежать большого объема памяти и избыточной глубины рекурсии. Определенная бинарная операция
A op B
теперь может быть объединена с другим элементомop C
, и полученная структура будет «уплощена», так что представление, а также компиляция SQL не требуют рекурсии.Одним из следствий этого изменения является то, что выражения конкатенации строк, использующие функции SQL, получаются «плоскими», например, MySQL теперь будет выводить
concat('x', 'y', 'z', ...)`
, а не вложенные друг в друга двухэлементные функции типаconcat(concat('x', 'y'), 'z')
. Сторонние диалекты, переопределяющие оператор конкатенации строк, должны будут реализовать новый методdef visit_concat_op_expression_clauselist()
в дополнение к существующему методуdef visit_concat_op_binary()
.References: #7744
Реализована полная поддержка операций «truediv» и «floordiv» с использованием операторов «/» и «//». Теперь операция «truediv» между двумя выражениями, использующими
Integer
, считает результатNumeric
, а компиляция на уровне диалекта приведет правый операнд к числовому типу в зависимости от диалекта, чтобы обеспечить truediv. Для floordiv также добавлено преобразование для тех баз данных, которые по умолчанию не используют floordiv (MySQL, Oracle), и в этом случае приводится функцияFLOOR()
, а также для случаев, когда правый операнд не является целым числом (необходимо для PostgreSQL и др.).Данное изменение решает проблемы, связанные как с несогласованным поведением оператора деления на различных бэкендах, так и устраняет проблему, когда при целочисленном делении на Oracle не удавалось получить результат из-за некорректных обработчиков типа вывода.
См.также
Оператор деления в Python выполняет истинное деление для всех бэкендов; добавлено деление на пол
References: #4926
В компилятор добавлен дополнительный шаг поиска, который будет отслеживать все предложения FROM, являющиеся таблицами, которые могут иметь одно и то же имя, совместно используемое в нескольких схемах, где одна из схем является неявной схемой «по умолчанию»; в этом случае имя таблицы при обращении к этому имени без уточнения схемы будет отображаться анонимным псевдонимом на уровне компилятора, чтобы дезамбигировать эти два (или более) имени. Рассматривался также вариант схемной квалификации обычно неквалифицированного имени с помощью определяемого сервером значения «default schema name», однако этот подход не применим к Oracle, не принимается SQL Server и не работает при наличии нескольких записей в пути поиска PostgreSQL. Проблема столкновения имен, решенная в данной статье, была идентифицирована как влияющая, по крайней мере, на Oracle, PostgreSQL, SQL Server, MySQL и MariaDB.
References: #7471
Для строковых значений Python, для которых тип SQL определяется из типа значения, в основном при использовании
literal()
, теперь будет применяться типString
, а не тип данныхUnicode
, для строковых значений Python, которые тестируются как «ascii only» при использовании Pythonstr.isascii()
. Если строка неisascii()
, то вместо нее будет привязан тип данныхUnicode
, который ранее использовался во всех случаях определения строк. Такое поведение применимо только для определения типов данных на месте при использовании ``literal()`` или других контекстов, не имеющих существующего типа данных, чего обычно не происходит при обычных операциях сравненияColumn
, где тип сравниваемогоColumn
всегда имеет приоритет.Использование типа данных
Unicode
может определять форматирование литеральных строк на таких бэкендах, как SQL Server, где литеральное значение (т.е. использующееliteral_binds
) будет отображаться какN'<value>'
, а не как'value'
. Для обычной работы со связанными значениями тип данныхUnicode
также может иметь значение для передачи значений в DBAPI, опять же в случае SQL Server, драйвер pyodbc поддерживает использование setinputsizes mode, который будет по-разному обрабатыватьString
иUnicode
.References: #7551
Теперь
array_agg
будет устанавливать размерность массива равной 1. Улучшена обработкаARRAY
для приема значенийNone
в качестве значения мультимассива.References: #7083
schema¶
Расширение системы «условного DDL», реализованной в классе
ExecutableDDLElement
(переименованном изDDLElement
), для непосредственного использования в конструкцияхSchemaItem
, таких какIndex
,ForeignKeyConstraint
и т.д., таким образом, условная логика генерации этих элементов включается в процесс генерации DDL по умолчанию. Эта система также может быть реализована в будущем выпуске Alembic для поддержки условных элементов DDL во всех системах управления схемами.References: #7631
В конструкцию
DropConstraint
добавлен параметрDropConstraint.if_exists
, который приводит к добавлению в DDL оператора «IF EXISTS». DDL добавляется к оператору DROP. Эта фраза принимается не всеми базами данных, и операция будет неудачной в базе данных, которая ее не поддерживает, так как в рамках одного DDL-оператора нет аналогичного совместимого запасного варианта. Pull request любезно предоставлен Майком Фидлером.References: #8141
Реализованы крючки событий DDL
DDLEvents.before_create()
,DDLEvents.after_create()
,DDLEvents.before_drop()
,DDLEvents.after_drop()
для всех объектовSchemaItem
, включающих отдельный шаг CREATE или DROP, когда этот шаг вызывается как отдельный SQL-оператор, в том числе дляForeignKeyConstraint
,Sequence
,Index
иENUM
в PostgreSQL.References: #8394
Переработан API отражения схем, что позволяет использовать высокопроизводительные пакетные запросы для отражения схем многих таблиц одновременно, используя на порядок меньшее количество запросов. Новые возможности по производительности ориентированы в первую очередь на бэкенды PostgreSQL и Oracle и могут быть применены к любому диалекту, использующему для отражения таблиц запросы SELECT к таблицам системного каталога. Изменения также включают новые возможности API и улучшения поведения объекта
Inspector
, в том числе согласованное, кэшируемое поведение методовInspector.has_table()
,Inspector.get_table_names()
и новые методыInspector.has_schema()
иInspector.has_index()
.См.также
Основные улучшения архитектуры, производительности и API для отражения в базах данных - полный фон
References: #4379
Убраны предупреждения, выдаваемые при отражении индексов или уникальных ограничений, когда параметр
Table.include_columns
используется для исключения столбцов, которые затем оказываются частью этих ограничений. При использовании параметраTable.include_columns
следует ожидать, что результирующая конструкцияTable
не будет включать ограничения, опирающиеся на опущенные столбцы. Это изменение было внесено в ответ на предложение #8100, которое восстановилоTable.include_columns
в сочетании с ограничениями внешнего ключа, которые полагаются на опущенные столбцы, когда стало ясно, что следует ожидать исключения таких ограничений.References: #8102
Добавлена поддержка комментариев к объектам
Constraint
, включая DDL и reflection; поле добавляется в базовый классConstraint
и соответствующие конструкторы, однако PostgreSQL является единственным бэкендом, поддерживающим эту возможность в настоящее время. См. такие параметры, какForeignKeyConstraint.comment
,UniqueConstraint.comment
илиCheckConstraint.comment
.References: #5677
Добавлена поддержка отраженных опций Partitioning и Sample pages на MySQL и MariaDB. Опции хранятся в таблице dialect options dictionary, поэтому к следующему ключевому слову необходимо добавлять префикс
mysql_
илиmariadb_
в зависимости от бэкенда. Поддерживаются следующие опции:stats_sample_pages
partition_by
partitions
subpartition_by
Эти опции также отражаются при загрузке таблицы из базы данных и заполняют таблицу
Table.dialect_options
. Pull request любезно предоставлен Ramon Will.References: #4038
typing¶
Метод
TypeEngine.with_variant()
теперь возвращает копию исходного объектаTypeEngine
, а не оборачивает его внутри классаVariant
, который фактически удаляется (символ импорта остается для обратной совместимости с кодом, который может тестироваться на наличие этого символа). Хотя предыдущий подход сохранял поведение in-Python, сохранение исходного типа позволяет более четко проверять типы и выполнять отладку.TypeEngine.with_variant()
также допускает несколько имен диалектов в одном вызове, в частности, это полезно для связанных имен бэкендов, таких как"mysql", "mariadb"
.References: #6980
postgresql¶
Добавлен новый тип данных PostgreSQL
DOMAIN
, в котором реализовано то же поведение CREATE TYPE / DROP TYPE, что и в PostgreSQLENUM
. Большое спасибо Дэвиду Баумголду за проделанную работу.См.также
References: #7316
Добавлены переопределяемые методы
PGDialect_asyncpg.setup_asyncpg_json_codec
иPGDialect_asyncpg.setup_asyncpg_jsonb_codec
codec, которые решают необходимую задачу регистрации кодеков JSON/JSONB для этих типов данных при использовании asyncpg. Изменения заключаются в том, что методы разбиты на отдельные переопределяемые методы для поддержки сторонних диалектов, которым необходимо изменить или отключить настройку этих кодеков.This change is also backported to: 1.4.27
References: #7284
Добавлена визуализация литеральных типов для типов данных
ARRAY
иARRAY
. Для общего stringify будут использоваться скобки, например,[1, 2, 3]
, а для специфичного для PostgreSQL - литерал ARRAY, например,ARRAY[1, 2, 3]
. Также учитывается множественная размерность и цитирование.References: #8138
Добавлена поддержка многодиапазонных типов PostgreSQL, появившаяся в PostgreSQL 14. Поддержка диапазонов и мультидиапазонов PostgreSQL теперь обобщена на бэкенды psycopg3, psycopg2 и asyncpg, с возможностью дальнейшей поддержки диалектов, используя объект данных
Range
, не зависящий от бэкенда и совместимый по конструктору с ранее используемым объектом psycopg2. Примеры использования приведены в новой документации.Кроме того, улучшена обработка типов диапазонов, которая автоматически выполняет приведение типов. Таким образом, при обходе на месте операторов, не предоставляющих базе данных никакого контекста, не требуется явное использование конструкции
cast()
для того, чтобы база данных знала нужный тип (рассматривается в разделе #8540).Огромное спасибо @zeeeeeb за pull request, в котором реализованы и протестированы новые типы данных и поддержка psycopg.
Запрос «ping», выдаваемый при конфигурировании
create_engine.pool_pre_ping
для psycopg, asyncpg и pg8000, но не для psycopg2, был изменен на пустой запрос (;
) вместоSELECT 1
; кроме того, для драйвера asyncpg было исправлено ненужное использование подготовленного оператора для этого запроса. Это сделано для того, чтобы избавить PostgreSQL от необходимости составлять план запроса при выполнении ping. В настоящее время эта операция не поддерживается драйверомpsycopg2
, который продолжает использоватьSELECT 1
.References: #8491
Для работы SQLAlchemy теперь требуется PostgreSQL версии 9 или выше. Более ранние версии могут работать в некоторых ограниченных случаях.
Параметр
UUID.as_uuid
типаUUID
, ранее характерный для диалекта PostgreSQL, а теперь обобщенный для Core (вместе с новым бэкенд-агностическим типом данныхUuid
), теперь имеет значение по умолчаниюTrue
, что указывает на то, что объекты PythonUUID
по умолчанию принимаются этим типом данных. Кроме того, тип данных SQL ServerUNIQUEIDENTIFIER
был преобразован в тип, принимающий UUID; для устаревшего кода, использующегоUNIQUEIDENTIFIER
с помощью строковых значений, установите параметрUNIQUEIDENTIFIER.as_uuid
в значениеFalse
.References: #7225
Параметр
ENUM.name
для специфического для PostgreSQL типа данныхENUM
теперь является обязательным аргументом в виде ключевого слова. Имя» необходимо в любом случае для того, чтобыENUM
можно было использовать, так как при отсутствии «имени» на этапе рендеринга SQL/DDL будет возникать ошибка.Для поддержки новых возможностей PostgreSQL, включая диалект psycopg3, а также расширенную поддержку «быстрой вставки многих», система передачи информации о типе связанных параметров в базу данных PostgreSQL была переработана для использования встроенных кастов, выдаваемых компилятором SQL, и теперь применяется для всех диалектов PostgreSQL. В отличие от предыдущего подхода, при котором для приведения к виду использовался DBAPI, который в таких случаях, как pg8000 и адаптированный драйвер asyncpg, использовал метод pep-249
setinputsizes()
, а в случае драйвера psycopg2 в большинстве случаев полагался на сам драйвер, за некоторыми исключениями, сделанными для ARRAY.В соответствии с новым подходом, во всех диалектах PostgreSQL эти приведения выполняются по мере необходимости с использованием стиля PostgreSQL с двойной запятой в компиляторе, а использование
setinputsizes()
для диалектов PostgreSQL исключено, поскольку в любом случае это не было частью этих DBAPI (единственным исключением является pg8000, который добавил этот метод по просьбе разработчиков SQLAlchemy).К преимуществам такого подхода можно отнести производительность на каждом операторе, так как не требуется повторный проход по скомпилированному оператору во время выполнения, лучшую поддержку всех DBAPI, так как теперь существует единая последовательная система применения информации о типизации, и улучшенную прозрачность, так как вывод SQL-журнала, как и строковый вывод скомпилированного оператора, будет показывать эти приведения, присутствующие непосредственно в операторе, тогда как раньше эти приведения не были видны в выводе журнала, так как они возникали после регистрации оператора.
Оператор
Operators.match()
теперь используетplainto_tsquery()
для полнотекстового поиска в PostgreSQL, а неto_tsquery()
. Это сделано для того, чтобы обеспечить лучшую кросс-совместимость с поиском по другим базам данных. Полная поддержка всех полнотекстовых функций PostgreSQL остается доступной благодаря использованиюfunc
в сочетании сOperators.bool_op()
(улучшенная версияOperators.op()
для булевых операторов).References: #7086
Удалена поддержка нескольких устаревших драйверов:
pypostgresql для PostgreSQL. Он доступен в виде внешнего драйвера по адресу https://github.com/PyGreSQL.
pygresql для PostgreSQL.
Пожалуйста, перейдите на один из поддерживаемых драйверов или на внешнюю версию того же драйвера.
References: #7258
Добавлена поддержка диалекта
psycopg
, поддерживающего как синхронное, так и асинхронное выполнение. Этот диалект доступен под именемpostgresql+psycopg
для функций создания движковcreate_engine()
иcreate_async_engine()
.References: #6842
Обновление диалекта psycopg2 для использования интерфейса DBAPI для выполнения двухфазных транзакций. Ранее для обработки такого рода транзакций выполнялись SQL-команды.
References: #7238
Введен тип
JSONPATH
, который может использоваться в выражениях приведения. Это требуется в некоторых диалектах PostgreSQL при использовании таких функций, какjsonb_path_exists
илиjsonb_path_match
, которые принимают на входjsonpath
.См.также
Типы JSON - Типы PostgreSQL JSON.
References: #8216
Диалект PostgreSQL теперь поддерживает отражение индексов, основанных на выражениях. Отражение поддерживается как при использовании
Inspector.get_indexes()
, так и при отраженииTable
с помощьюTable.autoload_with
. Спасибо immerrr и Aidan Kane за помощь в работе над этим тикетом.References: #7442
mysql¶
Функция
ROLLUP
теперь будет корректно отображатьWITH ROLLUP
на MySql и MariaDB, что позволяет использовать group by rollup с этими бэкендами.References: #8503
Исправлена проблема в MySQL
Insert.on_duplicate_key_update()
, которая при использовании выражения в выражении VALUES приводила к неправильному отображению имени столбца. Pull request любезно предоставлен Кристианом Сабайлой.This change is also backported to: 1.4.27
References: #7281
Удалена поддержка драйвера OurSQL для MySQL и MariaDB, так как этот драйвер, похоже, не поддерживается.
References: #7258
mariadb¶
Добавлена новая опция выполнения
is_delete_using=True
, которая потребляется ORM при использовании оператора DELETE с поддержкой ORM в сочетании со стратегией синхронизации «fetch»; эта опция указывает, что в операторе DELETE предполагается использование нескольких таблиц, что для MariaDB является синтаксисом DELETE..USING. Далее опция указывает, что RETURNING (недавно реализованный в SQLAlchemy 2.0 для MariaDB для #7011) не должен использоваться для баз данных, которые, как известно, не поддерживают синтаксис «DELETE..USING..RETURNING», даже если они поддерживают «DELETE..USING», что является текущей возможностью MariaDB.Смысл этой опции заключается в том, что текущая работа DELETE с поддержкой ORM не знает заранее, относится ли оператор DELETE к нескольким таблицам или нет, пока не произойдет компиляция, которая в любом случае кэшируется, но это должно быть известно, чтобы SELECT для удаляемой строки мог быть выдан заранее. Вместо того чтобы накладывать штраф за производительность на все операторы DELETE, проверяя их все на наличие этого относительно необычного SQL-шаблона, опция выполнения
is_delete_using=True
запрашивается с помощью нового сообщения об исключении, которое выдается на этапе компиляции. Это сообщение об исключении выдается только в следующих случаях: оператор представляет собой ORM-совместимый DELETE, в котором была запрошена стратегия синхронизации «fetch»; бэкенд - MariaDB или другой бэкенд с этим специфическим ограничением; в процессе начальной компиляции было обнаружено, что в противном случае оператор выдаст «DELETE..USING..RETURNING». Применяя опцию выполнения, ORM понимает, что вместо этого нужно выполнить SELECT. Аналогичная опция реализована и для UPDATE с поддержкой ORM, но в настоящее время нет бэкенда, где она была бы необходима.References: #8344
Добавлена поддержка INSERT..RETURNING и DELETE..RETURNING для диалекта MariaDB. UPDATE..RETURNING пока не поддерживается MariaDB. MariaDB поддерживает INSERT..RETURNING начиная с версии 10.5.0 и DELETE..RETURNING начиная с версии 10.0.5.
References: #7011
sqlite¶
Добавлен новый параметр в SQLite для методов отражения
sqlite_include_internal=True
; при его отсутствии локальные таблицы, начинающиеся с префиксаsqlite_
, которые в документации SQLite отмечены как таблицы «внутренней схемы», например, таблицаsqlite_sequence
, созданная для поддержки столбцов «AUTOINCREMENT», не будут включаться в методы отражения, возвращающие списки локальных объектов. Это позволяет избежать проблем, например, при использовании автогенерации Alembic, которая ранее считала такие таблицы, сгенерированные SQLite, удаленными из модели.См.также
References: #8234
Добавлена поддержка RETURNING для диалекта SQLite. SQLite поддерживает RETURNING начиная с версии 3.35.
References: #6195
Диалект SQLite теперь поддерживает синтаксис UPDATE..FROM, позволяющий операторам UPDATE ссылаться на дополнительные таблицы в рамках критерия WHERE без использования подзапросов. Этот синтаксис автоматически вызывается при использовании конструкции
Update
, когда используется более одной таблицы или другой сущности или selectable.References: #7185
Теперь для разбора входящих значений строк времени, даты и времени в SQLite используются методы стандартной библиотеки Python lib
fromisoformat()
. Это повышает производительность по сравнению с предыдущим подходом, основанным на регулярных выражениях, а также автоматически учитывает форматы времени и даты, содержащие либо шестизначный формат «микросекунды», либо трехзначный формат «миллисекунды».References: #7029
Убрано предупреждение, выдаваемое типом
Numeric
, о том, что DBAPI не поддерживают нативно десятичные значения. Это предупреждение было ориентировано на SQLite, который не имеет реального способа без дополнительных расширений или обходных путей работать с числовыми значениями точности более 15 значащих цифр, поскольку использует для представления чисел только математику с плавающей точкой. Поскольку это известное и документированное ограничение в самом SQLite, а не причуда драйвера pysqlite, нет необходимости предупреждать SQLAlchemy об этом. В остальном данное изменение не изменяет работу с точными числами. Значения могут по-прежнему обрабатываться какDecimal()
илиfloat()
, как это настроено в типах данныхNumeric
,Float
и других, только без возможности поддерживать точность более 15 значащих цифр при использовании SQLite, если не используются альтернативные представления, например, строки.References: #7299
Диалект SQLite теперь по умолчанию принимает значение
QueuePool
при использовании базы данных на основе файлов. Это устанавливается вместе с установкой параметраcheck_same_thread
в значениеFalse
. Было замечено, что предыдущий подход, при котором по умолчанию устанавливалось значениеNullPool
, не удерживающее соединения с базой данных после их освобождения, действительно оказывал ощутимое негативное влияние на производительность. Как обычно, класс пула настраивается с помощью параметраcreate_engine.poolclass
.References: #7490
mssql¶
Реализовано отражение флага «кластеризованный индекс»
mssql_clustered
для диалекта SQL Server. Pull request любезно предоставлен Джоном Ленноксом.References: #8288
Добавлена поддержка комментариев таблиц и столбцов на MSSQL при создании таблицы. Добавлена поддержка отражения комментариев к таблицам. Спасибо Daniel Hall за помощь в этом pull request.
References: #7844
Параметр
use_setinputsizes
для диалектаmssql+pyodbc
теперь имеет значение по умолчаниюTrue
; это сделано для того, чтобы неюникодные сравнения строк привязывались pyodbc к pyodbc.SQL_VARCHAR, а не pyodbc.SQL_WVARCHAR, что позволяет использовать индексы к столбцам VARCHAR. Для того чтобы параметрfast_executemany=True
продолжал работать, режимuse_setinputsizes
теперь пропускает вызовcursor.setinputsizes()
именно тогда, когдаfast_executemany
имеет значение True, а конкретный используемый метод -cursor.executemany()
, который не поддерживает setinputsizes. Изменение также добавляет соответствующую типизацию pyodbc DBAPI для значений, типизированных какUnicode
илиUnicodeText
, а также изменяет базовый тип данныхJSON
для рассмотрения строковых значений JSON какUnicode
, а неString
.References: #8177
Удалена поддержка драйвера mxodbc из-за отсутствия тестирования. Пользователи ODBC могут использовать диалект pyodbc, который полностью поддерживается.
References: #7258
oracle¶
Добавить поддержку нового драйвера oracle
oracledb
.References: #8054
Реализована поддержка DDL и рефлексии для типов данных
FLOAT
, включающих явное значение «binary_precision». При использовании специфического для Oracle типа данныхFLOAT
можно указать новый параметрFLOAT.binary_precision
, который будет напрямую отображать точность Oracle для типов с плавающей точкой. Это значение интерпретируется при отражении. При отражении типа данныхFLOAT
возвращаемый тип данных будет одним из следующих:DOUBLE_PRECISION
дляFLOAT
с точностью 126 (это также точность Oracle по умолчанию дляFLOAT
),REAL
для точности 63 иFLOAT
для пользовательской точности, согласно документации Oracle.В рамках этого изменения общее значение
Float.precision
явно отвергается при генерации DDL для Oracle, поскольку такая точность не может быть точно преобразована в «двоичную точность»; вместо этого в сообщении об ошибке предлагается использоватьTypeEngine.with_variant()
, чтобы можно было точно выбрать специфическую форму точности Oracle. Это изменение поведения является обратно несовместимым, так как предыдущее значение «precision» молча игнорировалось для Oracle.References: #5465
Для диалекта cx_Oracle реализована полная поддержка «RETURNING», охватывающая два отдельных вида функциональности:
Реализовано многорядное ВОЗВРАЩЕНИЕ, т.е. теперь для операторов DML, создающих более одной строки для ВОЗВРАЩЕНИЯ, будет получено несколько строк ВОЗВРАЩЕНИЯ.
Реализована также функция «executemany RETURNING», позволяющая при использовании
cursor.executemany()
выдать строку за строку. Реализация этой части функции позволяет значительно повысить производительность ORM-вставок, подобно тому, как это было сделано для psycopg2 в изменении SQLAlchemy 1.4 ORM Пакетные вставки с psycopg2 теперь в большинстве случаев выполняют пакетные операции с RETURNING.
References: #6245
Теперь Oracle по умолчанию использует синтаксис FETCH FIRST N ROWS / OFFSET для поддержки ограничений/смещений в Oracle 12c и выше. Этот синтаксис уже был доступен при прямом использовании
Select.fetch()
, теперь он подразумевается и дляSelect.limit()
иSelect.offset()
.References: #8221
Материализованные представления в oracle теперь отражаются как представления. В предыдущих версиях SQLAlchemy представления возвращались среди имен таблиц, а не среди имен представлений. В качестве побочного эффекта этого изменения они не отражаются по умолчанию методом
MetaData.reflect()
, если не задан параметрviews=True
. Чтобы получить список материализованных представлений, используйте новый метод проверкиInspector.get_materialized_view_names()
.В диалектах cx_Oracle и oracledb внесены коррективы в типы данных BLOB / CLOB / NCLOB с целью повышения производительности на основе рекомендаций разработчиков Oracle.
References: #7494
В связи с устареванием
create_engine.implicit_returning
, функция «implicit_returning» теперь включена для диалекта Oracle во всех случаях; ранее эта функция отключалась при обнаружении версии Oracle 8/8i, однако в онлайн-документации указано, что обе версии поддерживают тот же синтаксис RETURNING, что и современные версии.References: #6962
cx_Oracle 7 теперь является минимальной версией для cx_Oracle.
misc¶
Удален внутренний диалект «sybase», который был устаревшим в предыдущих версиях SQLAlchemy. Поддержка сторонних диалектов доступна.
См.также
References: #7258
Удален внутренний диалект «firebird», который был устаревшим в предыдущих версиях SQLAlchemy. Поддержка сторонних диалектов доступна.
См.также
References: #7258