Рубрики
Без рубрики

Управляющие отношения в моделях данных SQLALCHEMY

Есть много веских причин использовать SQLALCHEMY, от управляющей базы данных Connect … Теги с Python, SoftWaredEvelopment, SQL.

Есть много веских причин для использования SQLALCHEMY, от управления соединениями базы данных к простым интеграциям с библиотеками, такими как Pandas. Если вы находитесь в бизнесе по созданию приложений, я был бы готов стать поставить, что управление данными вашего приложения через ORM находится в верхней части вашего списка используемых случаев для SQLALCHEMY.

Большинство инженеров программного обеспечения, вероятно, найдут управление моделью базы данных, чтобы быть проще, чем SQL-запросы. Для людей с тяжелым фоном данных (как и мы), дополнительные абстракции могут быть немного отталкивающими: почему мы нужен Иностранные ключи для выполнения соединений между двумя таблицами? Зачем нам нужно различать, когда таблицы будут иметь один ко многим отношения, в отличие от Многие для многих отношение? Эти вещи не ограничивают SQL, так что со всей «дополнительной работой»?

Точка использования ORM является результатом меньше Работа для людей, строительных приложений, переводя концепции базы данных в легко воспроизводимый код в нашем приложении. Сегодня мы проверим определение моделей данных SQLALCHEMY, с особым вниманием к управлению отношениями на столах.

Мы собираемся смотреть на ванильную SQLALCHEMY: если вы ищете руководство по реализации моделей данных SQLALCHEMY в колбе, вероятно, стоит проверить этот пост после вас сделал здесь.

Определение базовой модели

Прежде чем прыгать в определение отношений, давайте повторим, как определить базовую модель базы данных.

Модели базы данных SQLALCHEMY – это классы, которые расширяют базу SQLALCHEMY (такие как declarive_base () ), которую мы импортируем из SQLALCHEMY упаковка. Модели базы данных состоят из Колонны , которые являются типами данных, уникальными для SQLALCHEMY :

from sqlalchemy import Column, Integer, String, Text, DateTime, Float, Boolean, PickleType
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class ExampleModel(Base):
    """Data model example."""
    __tablename__ = "example_table"
    __table_args__ = {"schema": "example"}

    id = Column(Integer,
                primary_key=True,
                nullable=False)
    name = Column(String(100),
                  nullable=False)
    description = Column(Text,
                         nullable=True)
    join_date = Column(DateTime,
                       nullable=False)
    vip = Column(Boolean,
                 nullable=False)
    number = Column(Float,
                    nullable=False)
    data = Column(PickleType,
                  nullable=False)

    def __repr__ (self):
        return ''.format(self.id)

Приведенная выше создает модель, которая использует каждый тип столбца, доступный для нас через SQLALCHEMY Анкет Каждая модель базы данных, которую мы создаем, соответствует таблице, где каждый Колонка Объект в нашей модели представляет столбец в полученной таблице. Когда наше приложение инициализирует SQLALCHEMY, SQLALCHEMY создаст таблицы в нашей базе данных, чтобы соответствовать каждой модели (предполагая, что еще не существует).

Мы также устанавливаем пару дополнительных встроенных переменных в нашей модели. __tablename__ Определяет название полученной таблицы базы данных и __table_args__ Позволяет нам установить, в какой схеме Postgres наша таблица будет жить (если применимо).

Создание таблиц из наших моделей

С созданной нашей моделью нам нужно явно создать результирующую таблицу в нашей базе данных. Мы делаем это, позвонив create_all () на База Объект, который является объектом, наша модель расширяется. Вот быстрый сценарий, который позаботится об этом для нас:

from models import Base
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from os import environ

# Create engine
db_uri = environ.get('SQLALCHEMY_DATABASE_URI')
engine = create_engine(db_uri, echo=True)

# Create All Tables
Base.metadata.create_all(engine)

Я сохранил наши Примечание класс в файл с именем Models.py , где мы импортируем База от. Как только мы создадим наш двигатель, линия Base.metadata.Create_all (Двигатель) Затем создает все таблицы, связанные с нашими моделями.

Проверьте запрос SQL, который привел к примеру модели:

-- Sequence and defined type
CREATE SEQUENCE IF NOT EXISTS example.example_table_id_seq;

-- Table Definition
CREATE TABLE "example"."example_table" (
    "id" int4 NOT NULL DEFAULT nextval('example.example_table_id_seq'::regclass),
    "name" varchar(100) NOT NULL,
    "description" text,
    "join_date" timestamp NOT NULL,
    "vip" bool NOT NULL,
    "number" float8 NOT NULL,
    "data" float8 NOT NULL,
    PRIMARY KEY ("id")
);

Бонус: Добавление записи

Я знаю, что мы рассмотрели это, но На всякий случай: Вот как мы добавили экземпляр нашего Экзамена :

newModel = ExampleModel(name='todd',
                        description='im testing this',
                        vip=True,
                        join_date=datetime.now())
session.add(newModel)
session.commit()
print(newModel)

Этот скрипт должен вернуть <Пример модели 1> потому что мы добавили __repr__ Метод нашей модели модели данных:


Относительные отношения от одного ко многим

Отношения из одного ко многим (или многими к одному) являются, пожалуй, наиболее распространенным типом отношений базы данных. Примеры их включают Клиенты + заказы Отношения (где у одиночных клиентов есть несколько заказов) или Игрок + команда отношения (где игрока спортсмара принадлежит одной команде). Мы собираемся построить пару моделей, чтобы помочь продемонстрировать последнее.

Я собираюсь опубликовать фрагмент кода ниже, который, вероятно, не собирается принять много смысла на первый взгляд. Это нормально- Ничего из этого не доходит до кого -либо естественно_. _ Мы проведем это вместе:

from sqlalchemy import Column, Integer, String, Text, DateTime, Float, Boolean, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class PlayerModel(Base):
    """Data model for players."""
    __tablename__ = "sqlalchemy_tutorial_players"
    __table_args__ = {"schema": "example"}

    id = Column(Integer,
                primary_key=True,
                nullable=False)
    team_id = Column(Integer,
                     ForeignKey('example.sqlalchemy_tutorial_teams.id'),
                     nullable=False)
    name = Column(String(100),
                  nullable=False)
    position = Column(String(100),
                      nullable=False)

    # Relationships
    team = relationship("TeamModel")

    def __repr__ (self):
        return ''.format(self.id)

class TeamModel(Base):
    """Data model for people."""
    __tablename__ = "sqlalchemy_tutorial_teams"
    __table_args__ = {"schema": "example"}

    id = Column(Integer,
                primary_key=True,
                nullable=False)
    name = Column(String(100),
                  nullable=False)
    city = Column(String(100),
                  nullable=False)

    def __repr__ (self):
        return ''.format(self.id)

С летучей мыши есть несколько вещей, которые мы сделать распознавать. У нас есть две модели, состоящие из Столбец S: одна модель для Игроки, и другая модель для Команды. Здесь есть два дополнения, которые являются новыми.

Во-первых, у нас есть концепция Иностранные ключи (установлен на Playermodel ‘s Team_id столбец). Если вы знакомы с SQL, вы должны быть хорошими здесь. Если нет, подумайте об этом таким образом: внешний ключ является свойством столбца. Когда присутствует внешний ключ, мы говорим, что этот конкретный столбец обозначает A Отношения Между таблицами: наиболее распространенные элементы одной таблицы «принадлежат» элементам другой таблицы, например, когда Клиенты “Собственный” Заказы или когда Команды “Собственный” Игроки. В нашем примере мы говорим, что каждый Игрок имеет команда как указано их Team_id Анкет Таким образом, мы можем жениться на данных между нашими Игроки стол и наш команда Таблица.

Другая новая концепция здесь отношения Отношения дополняют иностранные ключи и являются способом рассказать нашему заявлению (не нашей базе данных), что мы строим отношения между двумя моделями. Обратите внимание, как стоимость нашего внешнего ключа является 'example.sqlalchemy_tutorial_teams.id : Пример Наша схема Postgres и sqlalchemy_tutorial_teams это имя таблицы для нашего команды Таблица. Сравните это с значением, которое мы переходим к нашему Отношения , что "TeamModel" : Имя класса целевой модели данных (не имя таблицы!). Иностранные ключи рассказывают SQL какие отношения мы строят, и отношения говорят наше приложение какие отношения мы строят. Нам нужно сделать обоими.

Точка всего этого – это способность легко выполнять объединения в нашем приложении. При использовании ORM мы не сможем сказать «Присоединяйтесь к этой модели с помощью этой модели», потому что наше приложение не имело представления, какие столбцы присоединяются к на Анкет Когда наши отношения указаны в наших моделях, мы можем сделать такие вещи, как присоединиться к двум таблицам вместе, не указав дополнительную информацию: SQLalchemy узнает, как присоединиться к таблицам/моделям, глядя на то, что мы устанавливаем в наших моделях данных (так как принудительно и отношения мы устанавливаем). Мы действительно просто сохраняем бремя борьбы с логикой, связанной с данными при создании бизнес-логики нашего приложения, определяя авансовые отношения.

SQLalchemy создает столы из моделей данных, если таблицы уже не существуют. Другими словами, если у нас есть неисправные отношения, в первый раз мы запустим наше приложение, сообщения об ошибках будут сохраняться во второй раз, когда мы запустим наше приложение, даже если мы думаем, что мы исправили проблему. Чтобы справиться со странными сообщениями об ошибках, попробуйте удалить таблицы SQL, прежде чем снова запустить ваше приложение, когда вносят изменения в модель.

Обратные ссылки

Определение отношений на модели данных позволяет нам получить доступ к свойствам соединенной модели через свойство на исходной модели. Если бы мы присоединялись к нашему Playermodel С нашей TeamModel , мы сможем получить доступ к свойствам команды игрока через Playermodel.team.name , где команда это имя наших отношений, и имя является свойством связанной модели.

Отношения, созданные таким образом, однонаправленные, поскольку мы можем получить доступ к деталям команды через игрока, но Не могу Доступ к деталям игрока из команды. Мы можем легко решить это, установив Ссыловая ссылка Анкет

При создании отношений мы можем пройти атрибут под названием Backref сделать отношения двунаправленными. Вот как мы модифицируем отношения, которые мы устанавливаем ранее:

 # Relationships
team = relationship("TeamModel", backref="player")

С Backref Присутствует, теперь мы можем получить доступ к деталям игрока команды, позвонив в TeamModel.Player Анкет

Выполнение соединения

После того, как вы успешно внедрили взаимосвязь между двумя моделями данных, лучший способ проверить вашу работу – выполнить соединение на этих моделях. Мы не будем тратить время, войдя в создание продвинутых запросов SQLALCHEMY ORM здесь, но, по крайней мере, мы можем проверить нашу работу:

def join_example():
    records = session.query(PlayerModel).\
        join(TeamModel, TeamModel.id == PlayerModel.team_id).all()
    for record in records:
        recordObject = {'name': record.name,
                        'position': record.position,
                        'team_name': record.team.name,
                        'team_city': record.team.city}
        print(recordObject)

Здесь мы присоединяемся к TeamModel на Playermodel , поэтому мы ссылаемся на все как свойство Playermodel Анкет Вот что это выводит с образца данных:

{'name': 'Joe McMan', 'position': 'Quarterback', 'team_name': 'The Piggers', 'team_city': 'Austin, TX'}

Многие отношения

Установка отношений иностранных ключей служит нам хорошо, когда мы ожидаем, что таблица в наших отношениях будет иметь только одну запись на несколько записей в другой таблице (т.е. один игрок на команду). Что если игроки могут принадлежать несколько Команды? Вот где все становится сложным.

Как вы, возможно, догадались, между таблицами возникают взаимосвязи, где n-количества записей из таблицы 1 могут быть связаны с n числом записей из таблицы 2. SQLALCHEMY достигает таких отношений, подобных этим через Ассоциационные таблицы. Таблица ассоциации – это таблица SQL, созданная для единственной цели объяснения этих отношений, и мы собираемся построить его.

Проверьте, как мы определяем Association_table переменная ниже:

from sqlalchemy import Column, Integer, String, ForeignKey, Table
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

association_table = Table('association', Base.metadata,
    Column('team_id', Integer, ForeignKey('example.sqlalchemy_tutorial_players.team_id')),
    Column('id', Integer, ForeignKey('example.sqlalchemy_tutorial_teams.id'))
)

class PlayerModel(Base):
    """Data model for players."""
    __tablename__ = "sqlalchemy_tutorial_players"
    __table_args__ = {"schema": "example"}

    id = Column(Integer,
                primary_key=True,
                unique=True,
                nullable=False)
    team_id = Column(Integer,
                     ForeignKey('example.sqlalchemy_tutorial_teams.id'),
                     nullable=False)
    name = Column(String(100),
                  nullable=False)
    position = Column(String(100),
                      nullable=False)

    # Relationships
    teams = relationship("TeamModel",
                         secondary=association_table,
                         backref="player")

    def __repr__ (self):
        return ''.format(self.id)

class TeamModel(Base):
    """Data model for people."""
    __tablename__ = "sqlalchemy_tutorial_teams"
    __table_args__ = {"schema": "example"}

    id = Column(Integer,
                primary_key=True,
                unique=True,
                nullable=False)
    name = Column(String(100),
                  nullable=False)
    city = Column(String(100),
                  nullable=False)

    def __repr__ (self):
        return ''.format(self.id)

Мы используем новый тип данных Таблица Чтобы определить таблицу, которая строит ассоциацию многих ко многим. Первый параметр, который мы передаем, – это имя полученной таблицы, которую мы называем ассоциация . Далее мы проходим Base.metadata Чтобы связать нашу таблицу с той же декларативной базой, которую расширяют наши модели данных. Наконец, мы создаем два столбца, которые служат иностранными ключами для каждой из таблиц, которые мы связываем: мы связываем Playermodel ‘s Team_id колонка с TeamModel ‘s ID столбец.

Суть того, что мы действительно делаем здесь, – это создание третьей таблицы, которая связывает две наши таблицы. Мы также могли бы достичь этого, создав третью модель данных, но создание таблицы ассоциации немного проще. С этого момента мы можем теперь запросить Association_table непосредственно получить записи из наших игроков и таблицы команд.

Последний шаг в реализации таблицы ассоциации – установить отношения на нашей модели данных. Обратите внимание, как мы установили Отношения на Playermodel Как мы делали ранее, но на этот раз мы устанавливаем Вторичный Атрибут, равный имени нашей таблицы ассоциации.

Оригинал: “https://dev.to/toddbirchard/managing-relationships-in-sqlalchemy-data-models-5200”