Automap

Определение расширения системы sqlalchemy.ext.declarative, которое автоматически генерирует отображенные классы и отношения на основе схемы базы данных, обычно, хотя и не обязательно, отражаемой.

Предполагается, что система AutomapBase обеспечивает быстрое и модернизированное решение проблемы, которую пытается решить и известная SQLSoup, - быструю и рудиментарную генерацию объектной модели из существующей базы данных «на лету». Решая проблему строго на уровне конфигурации маппера и полностью интегрируясь с существующими технологиями декларативных классов, AutomapBase стремится обеспечить хорошо интегрированный подход к проблеме оперативной автогенерации специальных маппингов.

Совет

Расширение Automap ориентировано на подход «нулевого объявления», когда полная модель ORM, включающая классы и предварительно именованные отношения, может быть сгенерирована «на лету» из схемы базы данных. Для приложений, которые все еще хотят использовать явное объявление классов, включая явные определения отношений в сочетании с отражением таблиц, лучше использовать класс DeferredReflection, описанный в Использование DeferredReflection.

Базовое использование

Простейший вариант использования - отражение существующей базы данных в новой модели. Мы создаем новый класс AutomapBase аналогично тому, как мы создаем декларативный базовый класс, используя automap_base(). Затем мы вызываем AutomapBase.prepare() на полученном базовом классе, просим его отразить схему и создать отображения:

from sqlalchemy.ext.automap import automap_base
from sqlalchemy.orm import Session
from sqlalchemy import create_engine

Base = automap_base()

# engine, suppose it has two tables 'user' and 'address' set up
engine = create_engine("sqlite:///mydatabase.db")

# reflect the tables
Base.prepare(autoload_with=engine)

# mapped classes are now created with names by default
# matching that of the table name.
User = Base.classes.user
Address = Base.classes.address

session = Session(engine)

# rudimentary relationships are produced
session.add(Address(email_address="foo@bar.com", user=User(name="foo")))
session.commit()

# collection-based relationships are by default named
# "<classname>_collection"
u1 = session.query(User).first()
print (u1.address_collection)

Выше, вызов AutomapBase.prepare() с передачей параметра AutomapBase.prepare.reflect указывает на то, что метод MetaData.reflect() будет вызван на коллекции MetaData декларативных базовых классов; затем для каждого жизнеспособного Table внутри MetaData будет автоматически сгенерирован новый сопоставленный класс. Объекты ForeignKeyConstraint, связывающие различные таблицы между собой, будут использованы для создания новых двунаправленных объектов relationship() между классами. Классы и связи следуют стандартной схеме именования, которую мы можем настраивать. На данный момент наше базовое отображение, состоящее из связанных классов User и Address, готово к использованию традиционным способом.

Примечание

Под жизнеспособной мы подразумеваем, что для сопоставления таблица должна иметь первичный ключ. Кроме того, если таблица определяется как чистая ассоциативная таблица между двумя другими таблицами, то она не будет отображаться напрямую, а будет сконфигурирована как таблица «многие-ко-многим» между отображениями двух ссылающихся таблиц.

Генерация отображений на основе существующих метаданных

В automap_base() можно передать заранее объявленный объект MetaData. Этот объект может быть сконструирован любым способом, в том числе программно, из сериализованного файла или из самого отражения с помощью MetaData.reflect(). Ниже мы проиллюстрируем сочетание отражения и явного объявления таблицы:

from sqlalchemy import create_engine, MetaData, Table, Column, ForeignKey
from sqlalchemy.ext.automap import automap_base
engine = create_engine("sqlite:///mydatabase.db")

# produce our own MetaData object
metadata = MetaData()

# we can reflect it ourselves from a database, using options
# such as 'only' to limit what tables we look at...
metadata.reflect(engine, only=['user', 'address'])

# ... or just define our own Table objects with it (or combine both)
Table('user_order', metadata,
                Column('id', Integer, primary_key=True),
                Column('user_id', ForeignKey('user.id'))
            )

# we can then produce a set of mappings from this MetaData.
Base = automap_base(metadata=metadata)

# calling prepare() just sets up mapped classes and relationships.
Base.prepare()

# mapped classes are ready
User, Address, Order = Base.classes.user, Base.classes.address,\
    Base.classes.user_order

Генерация отображений из нескольких схем

Метод AutomapBase.prepare() при использовании отражения может отражать таблицы не более чем из одной схемы, используя параметр AutomapBase.prepare.schema для указания имени схемы, из которой производится отражение. Чтобы заполнить AutomapBase таблицами из нескольких схем, метод AutomapBase.prepare() может быть вызван несколько раз, каждый раз передавая параметру AutomapBase.prepare.schema другое имя. Метод AutomapBase.prepare() ведет внутренний список объектов Table, которые уже были отображены, и добавляет новые отображения только для тех объектов Table, которые появились с момента последнего запуска AutomapBase.prepare():

e = create_engine("postgresql://scott:tiger@localhost/test")

Base.metadata.create_all(e)

Base = automap_base()

Base.prepare(e)
Base.prepare(e, schema="test_schema")
Base.prepare(e, schema="test_schema_2")

Добавлено в версии 2.0: Метод AutomapBase.prepare() может быть вызван любое количество раз, при этом при каждом запуске будут отображаться только вновь добавленные таблицы. Ранее, в версии 1.4 и более ранних версиях, многократный вызов метода приводил к ошибкам, поскольку он пытался повторно отобразить уже отображенный класс. Ранее использовавшийся обходной путь, заключавшийся в прямом вызове MetaData.reflect(), также остается доступным.

Автоматическое отображение одноименных таблиц в нескольких схемах

Для распространенного случая, когда несколько схем могут иметь таблицы с одинаковыми именами и, соответственно, порождать классы с одинаковыми именами, конфликты могут быть разрешены либо с помощью хука AutomapBase.prepare.classname_for_table для применения различных имен классов на основе каждой схемы, либо с помощью хука AutomapBase.prepare.modulename_for_table, который позволяет разотождествить классы с одинаковыми именами путем изменения их эффективного атрибута __module__. В приведенном ниже примере этот хук используется для создания атрибута __module__ для всех классов, имеющего вид mymodule.<schemaname>, где при отсутствии схемы используется имя схемы default:

e = create_engine("postgresql://scott:tiger@localhost/test")

Base.metadata.create_all(e)

def module_name_for_table(cls, tablename, table):
    if table.schema is not None:
        return f"mymodule.{table.schema}"
    else:
        return f"mymodule.default"

Base = automap_base()

Base.prepare(e, modulename_for_table=module_name_for_table)
Base.prepare(e, schema="test_schema", modulename_for_table=module_name_for_table)
Base.prepare(e, schema="test_schema_2", modulename_for_table=module_name_for_table)

Эти же именованные классы организованы в иерархическую коллекцию, доступную по адресу AutomapBase.by_module. Эта коллекция обходится по разделенному точками имени конкретного пакета/модуля до нужного имени класса.

Примечание

При использовании хука AutomapBase.prepare.modulename_for_table для возврата нового __module__, который не является None, класс не помещается в коллекцию AutomapBase.classes; сюда помещаются только классы, которым не было задано явное модульное имя, поскольку коллекция не может представлять одноименные классы по отдельности.

В приведенном выше примере, если база данных содержит таблицу с именем accounts во всех трех схемах: схеме по умолчанию, схеме test_schema и схеме test_schema_2, будут доступны три отдельных класса в виде:

Base.by_module.mymodule.default.accounts
Base.by_module.mymodule.test_schema.accounts
Base.by_module.mymodule.test_schema_2.accounts

По умолчанию для всех классов AutomapBase генерируется пространство имен модуля sqlalchemy.ext.automap. Если крючок AutomapBase.prepare.modulename_for_table не используется, то содержимое AutomapBase.by_module будет полностью находиться в пространстве имен sqlalchemy.ext.automap (например, MyBase.by_module.sqlalchemy.ext.automap.<classname>), которое будет содержать тот же ряд классов, что и в AutomapBase.classes. Поэтому, как правило, использовать AutomapBase.by_module необходимо только при наличии явных соглашений __module__.

Указание классов в явном виде

Совет

Если предполагается, что явные классы будут занимать важное место в приложении, то вместо них следует использовать DeferredReflection.

Расширение automap позволяет определять классы в явном виде, подобно тому, как это делается в классе DeferredReflection. Классы, расширяемые из AutomapBase, действуют как обычные декларативные классы, но не отображаются сразу после их создания, а отображаются при вызове AutomapBase.prepare(). Метод AutomapBase.prepare() будет использовать созданные нами классы в зависимости от имени таблицы, которую мы используем. Если наша схема содержит таблицы user и address, то мы можем определить один или оба класса, которые будут использоваться:

from sqlalchemy.ext.automap import automap_base
from sqlalchemy import create_engine

# automap base
Base = automap_base()

# pre-declare User for the 'user' table
class User(Base):
    __tablename__ = 'user'

    # override schema elements like Columns
    user_name = Column('name', String)

    # override relationships too, if desired.
    # we must use the same name that automap would use for the
    # relationship, and also must refer to the class name that automap will
    # generate for "address"
    address_collection = relationship("address", collection_class=set)

# reflect
engine = create_engine("sqlite:///mydatabase.db")
Base.prepare(autoload_with=engine)

# we still have Address generated from the tablename "address",
# but User is the same as Base.classes.User now

Address = Base.classes.address

u1 = session.query(User).first()
print (u1.address_collection)

# the backref is still there:
a1 = session.query(Address).first()
print (a1.user)

Выше мы проиллюстрировали переопределение одного из объектов relationship(), который должен был создать automap. Для этого нам нужно было убедиться, что имена совпадают с теми, которые обычно генерирует automap, т.е. имя отношения будет User.address_collection, а имя класса, на который ссылается automap, называется address, хотя мы в рамках использования этого класса ссылаемся на него как на Address.

Переопределение схем именования

Задача automap заключается в создании отображенных имен классов и отношений на основе схемы, что означает наличие точек принятия решений по определению этих имен. Эти три точки принятия решений обеспечиваются с помощью функций, которые могут быть переданы методу AutomapBase.prepare() и известны как classname_for_table(), name_for_scalar_relationship() и name_for_collection_relationship(). Любая из этих функций или все они могут быть предоставлены, как в приведенном ниже примере, где мы используем схему «верблюжьего регистра» для имен классов и «плюрализатор» для имен коллекций, используя пакет Inflect:

import re
import inflect

def camelize_classname(base, tablename, table):
    "Produce a 'camelized' class name, e.g. "
    "'words_and_underscores' -> 'WordsAndUnderscores'"

    return str(tablename[0].upper() + \
            re.sub(r'_([a-z])', lambda m: m.group(1).upper(), tablename[1:]))

_pluralizer = inflect.engine()
def pluralize_collection(base, local_cls, referred_cls, constraint):
    "Produce an 'uncamelized', 'pluralized' class name, e.g. "
    "'SomeTerm' -> 'some_terms'"

    referred_name = referred_cls.__name__
    uncamelized = re.sub(r'[A-Z]',
                         lambda m: "_%s" % m.group(0).lower(),
                         referred_name)[1:]
    pluralized = _pluralizer.plural(uncamelized)
    return pluralized

from sqlalchemy.ext.automap import automap_base

Base = automap_base()

engine = create_engine("sqlite:///mydatabase.db")

Base.prepare(autoload_with=engine,
            classname_for_table=camelize_classname,
            name_for_collection_relationship=pluralize_collection
    )

Из приведенного выше отображения мы теперь будем иметь классы User и Address, где коллекция из User в Address называется User.addresses:

User, Address = Base.classes.User, Base.classes.Address

u1 = User(addresses=[Address(email="foo@bar.com")])

Выявление взаимосвязей

Подавляющее большинство задач, решаемых с помощью automap, заключается в генерации структур relationship() на основе внешних ключей. Механизм, по которому это работает для отношений «многие-к-одному» и «один-ко-многим», выглядит следующим образом:

  1. Заданный Table, о котором известно, что он сопоставлен с определенным классом, проверяется на наличие объектов ForeignKeyConstraint.

  2. Из каждого ForeignKeyConstraint присутствующий удаленный объект Table сопоставляется с классом, к которому он должен быть сопоставлен, если таковой имеется, в противном случае он пропускается.

  3. Поскольку рассматриваемый нами ForeignKeyConstraint соответствует ссылке из непосредственного сопоставленного класса, отношение будет установлено как многие-к-одному, ссылающееся на сопоставленный класс; на сопоставленном классе будет создана соответствующая обратная ссылка один-ко-многим, ссылающаяся на данный класс.

  4. Если какой-либо из столбцов, входящих в ForeignKeyConstraint, не является нулевым (например, nullable=False), то к аргументам ключевого слова relationship.cascade, передаваемым в отношение или обратную ссылку, будет добавлен аргумент ключевого слова all, delete-orphan. Если в ForeignKeyConstraint сообщается, что ForeignKeyConstraint.ondelete установлен флаг CASCADE для not null или SET NULL для nullable набора столбцов, то в наборе аргументов ключевых слов отношения устанавливается флаг relationship.passive_deletes, равный True. Заметим, что не все бэкенды поддерживают отражение ON DELETE.

  5. Имена отношений определяются с помощью вызываемых функций AutomapBase.prepare.name_for_scalar_relationship и AutomapBase.prepare.name_for_collection_relationship. Важно отметить, что при именовании отношений по умолчанию имя выводится из имени реального класса. Если вы задали конкретному классу явное имя, объявив его, или указали альтернативную схему именования классов, то именно от этого имени будет зависеть имя отношения.

  6. Классы проверяются на наличие существующего сопоставленного свойства, соответствующего этим именам. Если таковое обнаруживается на одной стороне, но отсутствует на другой, AutomapBase пытается создать отношение на отсутствующей стороне, а затем использует параметр relationship.back_populates, чтобы указать новое отношение на другую сторону.

  7. В обычном случае, когда ни на одной из сторон нет отношений, AutomapBase.prepare() создает relationship() на стороне «многие-к-одному» и сопоставляет его с другим с помощью параметра relationship.backref.

  8. Производство relationship() и, опционально, backref() передается функции AutomapBase.prepare.generate_relationship, которая может быть поставлена конечным пользователем для дополнения аргументов, передаваемых в relationship() или backref(), или для использования собственных реализаций этих функций.

Аргументы пользовательских отношений

Хук AutomapBase.prepare.generate_relationship может быть использован для добавления параметров к отношениям. В большинстве случаев для возврата объекта можно воспользоваться существующей функцией generate_relationship(), дополнив заданный словарь ключевых слов собственными аргументами.

Ниже показано, как передать опции relationship.cascade и relationship.passive_deletes всем отношениям «один-ко-многим»:

from sqlalchemy.ext.automap import generate_relationship

def _gen_relationship(base, direction, return_fn,
                                attrname, local_cls, referred_cls, **kw):
    if direction is interfaces.ONETOMANY:
        kw['cascade'] = 'all, delete-orphan'
        kw['passive_deletes'] = True
    # make use of the built-in function to actually return
    # the result.
    return generate_relationship(base, direction, return_fn,
                                 attrname, local_cls, referred_cls, **kw)

from sqlalchemy.ext.automap import automap_base
from sqlalchemy import create_engine

# automap base
Base = automap_base()

engine = create_engine("sqlite:///mydatabase.db")
Base.prepare(autoload_with=engine,
            generate_relationship=_gen_relationship)

Отношения «многие-ко-многим

automap будет генерировать отношения «многие-ко-многим», например, те, которые содержат аргумент secondary. Процесс создания таких отношений выглядит следующим образом:

  1. Заданный Table проверяется на наличие объектов ForeignKeyConstraint, прежде чем ему будет присвоен какой-либо сопоставленный класс.

  2. Если таблица содержит два и ровно два объекта ForeignKeyConstraint, и все столбцы внутри этой таблицы являются членами этих двух объектов ForeignKeyConstraint, то таблица считается «вторичной», и не будет отображаться напрямую.

  3. Двум (или одной, для самореферентных) внешним таблицам, на которые ссылается Table, ставятся в соответствие классы, с которыми они будут сопоставлены, если таковые имеются.

  4. Если отображенные классы для обеих сторон расположены, то между ними создается двунаправленная пара многие-ко-многим relationship() / backref().

  5. Логика переопределения для many-to-many работает так же, как и для one-to-many/ many-to-one; функция generate_relationship() вызывается для генерации структур, а существующие атрибуты сохраняются.

Отношения с наследованием

automap не будет генерировать отношения между двумя классами, находящимися в отношениях наследования. То есть, если два класса заданы следующим образом:

class Employee(Base):
    __tablename__ = 'employee'
    id = Column(Integer, primary_key=True)
    type = Column(String(50))
    __mapper_args__ = {
         'polymorphic_identity':'employee', 'polymorphic_on': type
    }

class Engineer(Employee):
    __tablename__ = 'engineer'
    id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
    __mapper_args__ = {
        'polymorphic_identity':'engineer',
    }

Внешний ключ от Engineer к Employee используется не для отношения, а для установления объединенного наследования между двумя классами.

Обратите внимание, что это означает, что automap не будет генерировать любые отношения для внешних ключей, которые связывают подкласс с суперклассом. Если в отображении есть реальные связи от подкласса к суперклассу, то они должны быть явными. Ниже, поскольку у нас есть два отдельных внешних ключа от Engineer к Employee, нам необходимо задать как нужное нам отношение, так и inherit_condition, поскольку SQLAlchemy не может об этом догадаться:

class Employee(Base):
    __tablename__ = 'employee'
    id = Column(Integer, primary_key=True)
    type = Column(String(50))

    __mapper_args__ = {
        'polymorphic_identity':'employee', 'polymorphic_on':type
    }

class Engineer(Employee):
    __tablename__ = 'engineer'
    id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
    favorite_employee_id = Column(Integer, ForeignKey('employee.id'))

    favorite_employee = relationship(Employee,
                                     foreign_keys=favorite_employee_id)

    __mapper_args__ = {
        'polymorphic_identity':'engineer',
        'inherit_condition': id == Employee.id
    }

Обработка простых конфликтов именования

В случае возникновения конфликтов имен при отображении можно переопределить любое из значений classname_for_table(), name_for_scalar_relationship() и name_for_collection_relationship() при необходимости. Например, если automap пытается назвать отношение «многие-к-одному» так же, как и существующий столбец, можно условно выбрать альтернативное соглашение. Дана схема:

CREATE TABLE table_a (
    id INTEGER PRIMARY KEY
);

CREATE TABLE table_b (
    id INTEGER PRIMARY KEY,
    table_a INTEGER,
    FOREIGN KEY(table_a) REFERENCES table_a(id)
);

Приведенная схема сначала автоматизирует таблицу table_a как класс с именем table_a; затем автоматизирует отношение к классу для table_b с тем же именем, что и у этого связанного класса, например table_a. Это имя отношения конфликтует с колонкой отображения table_b.table_a, и при отображении будет выдана ошибка.

Мы можем разрешить это противоречие, используя знак подчеркивания следующим образом:

def name_for_scalar_relationship(base, local_cls, referred_cls, constraint):
    name = referred_cls.__name__.lower()
    local_table = local_cls.__table__
    if name in local_table.columns:
        newname = name + "_"
        warnings.warn(
            "Already detected name %s present.  using %s" %
            (name, newname))
        return newname
    return name


Base.prepare(autoload_with=engine,
    name_for_scalar_relationship=name_for_scalar_relationship)

В качестве альтернативы мы можем изменить имя на стороне столбца. Сопоставленные столбцы могут быть изменены с помощью техники, описанной в Явное именование декларативных сопоставленных столбцов, путем явного присвоения столбцу нового имени:

Base = automap_base()

class TableB(Base):
    __tablename__ = 'table_b'
    _table_a = Column('table_a', ForeignKey('table_a.id'))

Base.prepare(autoload_with=engine)

Использование Automap с явными объявлениями

Как уже отмечалось, automap не зависит от рефлексии и может использовать любую коллекцию объектов Table внутри коллекции MetaData. Отсюда следует, что automap может быть использован и для генерации недостающих отношений в полной модели, полностью определяющей метаданные таблицы:

from sqlalchemy.ext.automap import automap_base
from sqlalchemy import Column, Integer, String, ForeignKey

Base = automap_base()

class User(Base):
    __tablename__ = 'user'

    id = Column(Integer, primary_key=True)
    name = Column(String)

class Address(Base):
    __tablename__ = 'address'

    id = Column(Integer, primary_key=True)
    email = Column(String)
    user_id = Column(ForeignKey('user.id'))

# produce relationships
Base.prepare()

# mapping is complete, with "address_collection" and
# "user" relationships
a1 = Address(email='u1')
a2 = Address(email='u2')
u1 = User(address_collection=[a1, a2])
assert a1.user is u1

Выше, при наличии в основном полных отображений User и Address, ForeignKey, определенный нами на Address.user_id, позволил сформировать на сопоставленных классах пары двунаправленных отношений Address.user и User.address_collection.

Заметим, что при подклассификации AutomapBase обязателен метод AutomapBase.prepare(), если его не вызвать, то объявленные нами классы окажутся в не отображенном состоянии.

Определения перехватывающих колонок

Объекты MetaData и Table поддерживают крючок событий DDLEvents.column_reflect(), который может быть использован для перехвата информации, отраженной о столбце базы данных, до того, как будет построен объект Column. Например, если мы хотим отобразить столбцы, используя соглашение об именовании, такое как "attr_<columnname>", то событие может быть применено в виде:

@event.listens_for(Base.metadata, "column_reflect")
def column_reflect(inspector, table, column_info):
    # set column.key = "attr_<lower_case_name>"
    column_info['key'] = "attr_%s" % column_info['name'].lower()

# run reflection
Base.prepare(autoload_with=engine)

Добавлено в версии 1.4.0b2: событие DDLEvents.column_reflect() может быть применено к объекту MetaData.

Справочник по API

Object Name Description

automap_base([declarative_base], **kw)

Создать декларативную базу автоматов.

AutomapBase

Базовый класс для схемы «automap».

classname_for_table(base, tablename, table)

Возвращает имя класса, который должен быть использован при задании имени таблицы.

generate_relationship(base, direction, return_fn, attrname, ..., **kw)

Генерировать relationship() или backref() от имени двух сопоставленных классов.

name_for_collection_relationship(base, local_cls, referred_cls, constraint)

Возвращает имя атрибута, который должен использоваться для ссылки от одного класса к другому, для ссылки на коллекцию.

name_for_scalar_relationship(base, local_cls, referred_cls, constraint)

Возвращает имя атрибута, которое должно использоваться для ссылки из одного класса в другой, для скалярной ссылки на объект.

function sqlalchemy.ext.automap.automap_base(declarative_base: Optional[Type[Any]] = None, **kw: Any) Any

Создать декларативную базу автоматов.

Эта функция создает новый базовый класс, который является продуктом класса AutomapBase, а также декларативной базы, создаваемой функцией declarative_base().

Все параметры, кроме declarative_base, являются аргументами ключевого слова, которые передаются непосредственно в функцию declarative_base().

Параметры:
  • declarative_base – существующий класс, созданный declarative_base(). При передаче этого аргумента функция больше не вызывает саму declarative_base(), а все остальные аргументы ключевого слова игнорируются.

  • **kw – аргументы ключевого слова передаются в declarative_base().

class sqlalchemy.ext.automap.AutomapBase

Базовый класс для схемы «automap».

Класс AutomapBase можно сравнить с «декларативным базовым» классом, который создается функцией declarative_base(). На практике класс AutomapBase всегда используется в качестве миксина наряду с реальной декларативной базой.

Новый подклассифицируемый AutomapBase обычно инстанцируется с помощью функции automap_base().

См.также

Automap

attribute sqlalchemy.ext.automap.AutomapBase.by_module: ClassVar[ByModuleProperties]

Экземпляр Properties, содержащий иерархическую структуру из разделенных точками имен модулей, связанных с классами.

Эта коллекция является альтернативой коллекции AutomapBase.classes, что удобно при использовании параметра AutomapBase.prepare.modulename_for_table, который будет применять к генерируемым классам отдельные атрибуты __module__.

По умолчанию __module__ генерируемого автоматом класса является sqlalchemy.ext.automap; обращение к этому пространству имен с помощью AutomapBase.by_module выглядит следующим образом:

User = Base.by_module.sqlalchemy.ext.automap.User

Если класс имел __module__ из mymodule.account, то обращение к этому пространству имен выглядит так:

MyClass = Base.by_module.mymodule.account.MyClass

Добавлено в версии 2.0.

attribute sqlalchemy.ext.automap.AutomapBase.classes: ClassVar[Properties[Type[Any]]]

Экземпляр Properties, содержащий классы.

Этот объект ведет себя подобно коллекции .c в таблице. Классы представлены под тем именем, которое им было присвоено, например:

Base = automap_base()
Base.prepare(autoload_with=some_engine)

User, Address = Base.classes.User, Base.classes.Address
attribute sqlalchemy.ext.automap.AutomapBase.metadata: ClassVar[MetaData]

Ссылается на коллекцию MetaData, которая будет использоваться для новых объектов Table.

classmethod sqlalchemy.ext.automap.AutomapBase.prepare(autoload_with: Optional[Engine] = None, engine: Optional[Any] = None, reflect: bool = False, schema: Optional[str] = None, classname_for_table: Optional[PythonNameForTableType] = None, modulename_for_table: Optional[PythonNameForTableType] = None, collection_class: Optional[Any] = None, name_for_scalar_relationship: Optional[NameForScalarRelationshipType] = None, name_for_collection_relationship: Optional[NameForCollectionRelationshipType] = None, generate_relationship: Optional[GenerateRelationshipType] = None, reflection_options: Union[Dict[_KT, _VT], immutabledict[_KT, _VT]] = {}) None

Извлечение сопоставленных классов и отношений из MetaData и выполнение сопоставления.

Полная документация и примеры приведены в разделе Базовое использование.

Параметры:
  • autoload_withEngine или Connection, с помощью которого выполняется отражение схемы; при указании метода в области действия этого метода будет вызван метод MetaData.reflect().

  • engine – legacy; use AutomapBase.autoload_with. Используется для указания Engine или Connection, с помощью которых следует отражать таблицы, если AutomapBase.reflect имеет значение True. … deprecated:: 1.4 Параметр AutomapBase.prepare.engine является устаревшим и будет удален в одном из следующих выпусков. Пожалуйста, используйте параметр AutomapBase.prepare.autoload_with.

  • reflect – legacy; use AutomapBase.autoload_with. Указывает на необходимость вызова MetaData.reflect(). … deprecated:: 1.4 Параметр AutomapBase.prepare.reflect является устаревшим и будет удален в будущем выпуске. Отражение включается, когда передается AutomapBase.prepare.autoload_with.

  • classname_for_table – вызываемая функция, которая будет использоваться для создания новых имен классов при заданном имени таблицы. По умолчанию принимает значение classname_for_table().

  • modulename_for_table – вызываемая функция, которая будет использоваться для получения эффективного значения __module__ для внутреннего класса, что позволяет использовать в одной базе automap несколько одноименных классов, которые будут находиться в разных «модулях». По умолчанию имеет значение None, что указывает на то, что __module__ не будет задаваться явно; среда выполнения Python будет использовать для этих классов значение sqlalchemy.ext.automap. При назначении __module__ сгенерированным классам доступ к ним можно получить на основе имен модулей, разделенных точками, с помощью коллекции AutomapBase.by_module. Классы, которым явно назначен __module_ с помощью этого хука, не помещаются в коллекцию AutomapBase.classes, а только в AutomapBase.by_module. … версия добавлена:: 2.0 .. seealso:: Генерация отображений из нескольких схем

  • name_for_scalar_relationship – вызываемая функция, которая будет использоваться для создания имен отношений для скалярных отношений. По умолчанию имеет значение name_for_scalar_relationship().

  • name_for_collection_relationship – вызываемая функция, которая будет использоваться для создания имен отношений для отношений, ориентированных на коллекции. По умолчанию имеет значение name_for_collection_relationship().

  • generate_relationship – вызываемая функция, которая будет использоваться для фактической генерации конструкций relationship() и backref(). По умолчанию используется generate_relationship().

  • collection_class – класс коллекции Python, который будет использоваться при создании нового объекта relationship(), представляющего коллекцию. По умолчанию принимается значение list.

  • schema – Имя схемы, отражаемое при отражении таблиц с помощью параметра AutomapBase.prepare.autoload_with. Это имя передается в параметр MetaData.reflect.schema параметра MetaData.reflect(). Если это имя опущено, то используется схема по умолчанию, используемая при подключении к базе данных. … note:: Параметр AutomapBase.prepare.schema поддерживает отражение только одной схемы за раз. Для включения таблиц из многих схем необходимо использовать несколько вызовов AutomapBase.prepare(). Обзор многосхемной автоматизации, включая использование дополнительных соглашений об именовании для разрешения конфликтов имен таблиц, приведен в разделе Генерация отображений из нескольких схем. … versionadded:: 2.0 AutomapBase.prepare() поддерживает прямой вызов любое количество раз, отслеживая таблицы, которые уже были обработаны, чтобы не обрабатывать их второй раз.

  • reflection_options – Когда он присутствует, этот словарь опций будет передан в MetaData.reflect() для предоставления общих опций, специфичных для отражения, таких как only, и/или опций, специфичных для диалекта, таких как oracle_resolve_synonyms. … versionadded:: 1.4

function sqlalchemy.ext.automap.classname_for_table(base: Type[Any], tablename: str, table: Table) str

Возвращает имя класса, который должен быть использован при задании имени таблицы.

По умолчанию реализовано:

return str(tablename)

Альтернативные реализации могут быть указаны с помощью параметра AutomapBase.prepare.classname_for_table.

Параметры:
  • base – класс AutomapBase, выполняющий подготовку.

  • tablename – строковое имя Table.

  • table – сам объект Table.

Результат:

строковое имя класса. …примечание:: В Python 2 строка, используемая для имени класса, должна быть неюникодным объектом, например, объектом str(). Атрибут .name объекта Table обычно является подклассом Python unicode, поэтому к этому имени должна быть применена функция str() после учета всех не-ASCII символов.

function sqlalchemy.ext.automap.name_for_scalar_relationship(base: Type[Any], local_cls: Type[Any], referred_cls: Type[Any], constraint: ForeignKeyConstraint) str

Возвращает имя атрибута, которое должно использоваться для ссылки из одного класса в другой, для скалярной ссылки на объект.

По умолчанию реализовано:

return referred_cls.__name__.lower()

Альтернативные реализации могут быть указаны с помощью параметра AutomapBase.prepare.name_for_scalar_relationship.

Параметры:
  • base – класс AutomapBase, выполняющий подготовку.

  • local_cls – класс, который должен быть отображен на локальной стороне.

  • referred_cls – класс, который должен быть отображен на передающей стороне.

  • constraintForeignKeyConstraint, которая проверяется для получения этого отношения.

function sqlalchemy.ext.automap.name_for_collection_relationship(base: Type[Any], local_cls: Type[Any], referred_cls: Type[Any], constraint: ForeignKeyConstraint) str

Возвращает имя атрибута, который должен использоваться для ссылки от одного класса к другому, для ссылки на коллекцию.

По умолчанию реализовано:

return referred_cls.__name__.lower() + "_collection"

Альтернативные реализации могут быть указаны с помощью параметра AutomapBase.prepare.name_for_collection_relationship.

Параметры:
  • base – класс AutomapBase, выполняющий подготовку.

  • local_cls – класс, который должен быть отображен на локальной стороне.

  • referred_cls – класс, который должен быть отображен на передающей стороне.

  • constraintForeignKeyConstraint, которая проверяется для получения этого отношения.

function sqlalchemy.ext.automap.generate_relationship(base: Type[Any], direction: RelationshipDirection, return_fn: Union[Callable[..., Relationship[Any]], Callable[..., ORMBackrefArgument]], attrname: str, local_cls: Type[Any], referred_cls: Type[Any], **kw: Any) Union[Relationship[Any], ORMBackrefArgument]

Генерировать relationship() или backref() от имени двух сопоставленных классов.

Альтернативная реализация этой функции может быть задана с помощью параметра AutomapBase.prepare.generate_relationship.

По умолчанию эта функция реализуется следующим образом:

if return_fn is backref:
    return return_fn(attrname, **kw)
elif return_fn is relationship:
    return return_fn(referred_cls, **kw)
else:
    raise TypeError("Unknown relationship function: %s" % return_fn)
Параметры:
  • base – класс AutomapBase, выполняющий подготовку.

  • direction – указывают «направление» связи; это будет одно из ONETOMANY, MANYTOONE, MANYTOMANY.

  • return_fn – функция, которая по умолчанию используется для создания отношения. Это будет либо relationship(), либо backref(). Результат функции backref() будет использован для создания новой relationship() на втором шаге, поэтому очень важно, чтобы пользовательские реализации правильно различали эти две функции, если используется пользовательская функция отношения.

  • attrname – имя атрибута, которому присваивается данное отношение. Если значением generate_relationship.return_fn является функция backref(), то это имя является именем, которому присваивается обратная ссылка.

  • local_cls – «локальный» класс, для которого данное отношение или обратная ссылка будет присутствовать локально.

  • referred_cls – «ссылающийся» класс, на который ссылается данное отношение или обратная ссылка.

  • **kw – все дополнительные аргументы ключевого слова передаются в функцию.

Результат:

конструкцию relationship() или backref(), что диктуется параметром generate_relationship.return_fn.

Back to Top