Что такое объектно-реляционное сопоставление?

Объектно-реляционное сопоставление (ORM) - это метод, используемый для сопоставления объектов с базой данных. С помощью ORM мы можем напрямую создавать таблицы с классами и данные в таблицах с созданными объектами (экземпляром класса). Этот метод программирования предоставляет стандартный интерфейс, который позволяет разработчикам создавать код, который можно использовать для взаимодействия с широким спектром механизмов баз данных, а не настраивать для каждого отдельного механизма базы данных.

SQLAlchemy

SQLAlchemhy, одна из реализаций ORM в Python, представляет собой библиотеку, которая облегчает взаимодействие между программами Python и различными механизмами баз данных, и она будет использоваться в этой статье для сохранения и запроса данных. Для меня два основных преимущества использования ORM заключаются в том, что он позволяет мне полностью избегать написания sql-запросов в моем коде (не потому, что я ненавижу sql), а также гарантирует, что я могу написать общий код, который можно использовать с различные механизмы реляционных баз данных (с небольшими настройками или без них, если нам нужно изменить ядро ​​базы данных). Некоторые из функций, обеспечивающих эту возможность работы с несколькими ядрами баз данных, будут обсуждаться в следующих разделах.

Типы данных SQLAlchemy

SQLAlchemy обеспечивает поддержку неявного и явного указания типа данных столбца. Он делает это, разрешая общее сопоставление типов данных Python с наиболее распространенными типами данных, обнаруженными в столбце реляционных баз данных, так что SQLAlchemy выберет лучший тип столбца базы данных, доступный в целевой базе данных, и сопоставит его с конкретным типом данных Python, как показано ниже;

  • Целое число () - ЦЕЛОЕ
  • String () - Строки ASCII - VARCHAR
  • Unicode () - строка Unicode - VARCHAR или NVARCHAR в зависимости от базы данных
  • Boolean () - BOOLEAN, INT, TINYINT в зависимости от поддержки db для логического типа
  • DateTime () - DATETIME или TIMESTAMP возвращает объекты Python datetime ().
  • Float () - значения с плавающей запятой
  • Numeric () - числа точности с использованием Python Decimal ()

Кроме того, он позволяет явно указать тип данных, используя стандартный синтаксис SQL или синтаксис, общий для подмножества баз данных для типов данных. Кроме того, он также предоставляет способ указать типы, зависящие от поставщика, такие как BIGINT для MySQL и INET для PostgreSQL.

SQLAlchemy Engine

SQLAlchemy Engine является отправной точкой для любого приложения SQLAlchemy, поскольку нам нужно создавать Engine всякий раз, когда мы хотим использовать SQLAlchemy для взаимодействия с базой данных. Движки создаются путем запуска функции create_engine, импортированной из sqlalchemy. Эта функция принимает URI базы данных (диалект + драйвер: // имя пользователя: пароль @ хост: порт / база данных) для создания объекта Engine. Однажды созданный движок может использоваться либо для прямого взаимодействия с базой данных, либо может быть передан объекту Session для работы с ORM. В этой статье мы передадим наш движок объекту Session, поскольку мы обсуждаем ORM. Обратите внимание, что функция create_engine не устанавливает никаких фактических соединений DBAPI напрямую. Engine относится к пулу соединений, что означает, что при нормальных обстоятельствах есть открытые соединения с базой данных, в то время как объект Engine все еще находится в памяти. Пул соединений - это способ поддерживать в памяти пул активных соединений с базой данных. Таким образом, для фактического подключения к базе данных необходимо вызвать метод подключения объекта Engine или операцию, зависящую от этого метода. Этот метод приводит к использованию одного из подключений к базе данных в пуле для подключения к базе данных.

Пулы соединений SQLAlchemy

Пул соединений - это реализация шаблона проектирования пула объектов. Пул объектов - это способ кэширования объектов для повторного использования. Шаблон проектирования пула объектов предлагает значительное повышение производительности, особенно в ситуациях, когда стоимость инициализации экземпляра класса высока. Кроме того, пул может автоматически увеличиваться за счет создания новых объектов, когда пул пуст и в пул отправляется запрос на объект, или пулы могут быть ограничены количеством созданных объектов. Следовательно, пул соединений - это стандартный метод, используемый для поддержания длительных соединений в памяти для эффективного повторного использования, а также для обеспечения управления общим количеством соединений, которые приложение может использовать одновременно. SQLAlchemy реализует различные шаблоны пула соединений. Движок, возвращаемый функцией create_engine, в большинстве случаев имеет QueuePool, который имеет разумные значения по умолчанию для объединения.

SQLAlchemy Диалекты

SQLAlchemy Dialects используется SQLAlchemy для связи с различными реализациями спецификации API базы данных Python (DBAPI). DBAPI определяет стандартный интерфейс для доступа к базам данных для модулей / библиотек, разработанных на Python. SQLAlchemy Dialects описывает, как взаимодействовать с конкретным типом комбинации базы данных / DBAPI. Некоторые реализации DBAPI - это pyscopg2 и mysql-connector-python для PostgreSQL и MySQL соответственно. ПРИМЕЧАНИЕ. Все диалекты требуют установки соответствующего DBAPI.

Стандартные и поддерживаемые диалекты SQLAlchemy:

  • PostgreSQL
  • MySQL
  • SQLite
  • Oracle
  • Microsoft SQL Server

ПРИМЕЧАНИЕ. Существует больше диалектов SQLAlchemy.

Базовые шаблоны отношений SQLAlchemy

Теперь мы можем использовать все, что мы узнали до сих пор, чтобы сопоставить отношения между классами отношениям между таблицами. SQLAlchemy поддерживает четыре типа отношений: один к одному, один ко многим, многие к одному и многие ко многим. Эти отношения будут реализованы дальше. Но перед этим нам нужно установить некоторые библиотеки и запустить настоящую базу данных, чтобы запрашивать данные в SQLAlchemy. Как мы уже знаем, SQLAlchemy поддерживает множество различных движков баз данных, но мы будем работать с PostgreSQL. Но сначала давайте создадим новый каталог и виртуальную среду для нашего проекта следующим образом:

>> mkdir object-relational-mapping 
>> cd object-relational-mapping 
>> python3 –m venv orm-venv 
>> venv/Scripts/activate

Первая и вторая команды выше создают каталог проекта (объектно-реляционное сопоставление) и изменяют каталог соответственно, а третья и четвертая команды создают виртуальную среду и активируют виртуальную среду соответственно.

Установка SQLAlchemy и его зависимостей

Во-первых, помните, что для всех диалектов требуется установка соответствующего DBAPI, и, поскольку мы будем работать с ядром базы данных PostgreSQL, нам нужно установить psycopg2, который является наиболее распространенной реализацией DBAPI для подключения к движку PostgreSQL. Кроме того, SQLAlchemy не является частью стандартной библиотеки Python, поэтому нам также необходимо установить ее. Это единственные две библиотеки, которые потребуются на самом деле, поэтому для установки этих библиотек в нашу виртуальную среду мы будем использовать pip следующим образом:

>> pip install sqlalchemy psycopg2

Запуск PostgreSQL

Есть несколько способов получить экземпляр движка базы данных PostgreSQL. В этом руководстве мы будем использовать службу RDS в Amazon Web Services (AWS). Другой вариант - установить PostgreSQL локально в нашей текущей среде. Итак, чтобы создать экземпляр PostgreSQL на AWS, вам необходимо создать учетную запись на AWS, если у вас ее еще нет. ПРИМЕЧАНИЕ. В этом примере мы будем оставаться в рамках лимита бесплатного уровня на AWS. Итак, как только мы вошли в нашу учетную запись AWS, щелкните сервисы на панели навигации, а затем щелкните RDS в разделе «База данных». На открывшейся новой странице нажмите «Создать базу данных». Затем выполните следующие шаги, чтобы создать экземпляр БД;

  • Заполните следующие поля; Идентификатор инстанса БД, главное имя пользователя, главный пароль и подтверждение пароля
  • Затем прокрутите вниз до «Дополнительная конфигурация подключения» и щелкните стрелку, чтобы отобразить настройки в этой категории, затем нажмите «Да» в разделе «Общедоступный», чтобы мы могли подключиться к базе данных извне.
  • Также прокрутите вниз до «Дополнительная конфигурация» и щелкните стрелку, чтобы отобразить все настройки в этой категории, а затем заполните поле «Исходное имя базы данных».
  • Наконец, нажмите «Создать базу данных» и подождите несколько минут, пока статус вашей базы данных не изменится на «Доступен».
  • Как только база данных станет доступной, вы можете щелкнуть по ней, чтобы найти «конечную точку», которая будет использоваться для подключения к базе данных. Эта конечная точка находится на вкладке «Подключение и безопасность» после нажатия на вновь созданную базу данных.

ПРИМЕЧАНИЕ. Не забудьте удалить базу данных после примера, чтобы не понести никаких расходов.

Классы сопоставления для создания отношений

Здесь мы будем реализовывать отношения «один ко многим», и идеи о том, как расширить пример, чтобы реализовать другие отношения, будут упомянуты для всех, кто захочет это сделать. Этот пример основан на создании двух таблиц базы данных; клубы и игроки. Таблица клубов будет состоять из футбольных клубов, а таблица игроков будет содержать футболистов, и соотношение будет таким, что футболисты могут играть только за клуб, в то время как клуб может состоять из нескольких игроков. Во-первых, давайте создадим базовый файл для создания нашего движка, а затем сеанс, чтобы иметь возможность работать с ORM. Кроме того, мы определим базовый класс в базовом файле, от которого наши классы Python будут наследовать, чтобы создавать соответствующие таблицы базы данных. Содержимое базового файла показано ниже;

base.py

from sqlalchemy import create_engine 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy.orm import sessionmaker 
#creating our engine 
engine = create_engine('postgresql+psycopg2://yinka:[email protected]:5432/orm') 
#remember that the engine needs to be passed to a Session object in order to be able to work with the ORM 
Session = sessionmaker(bind=engine) 
#the base class for defining our classes in order to produce the appropriate Tables 
Base = declarative_base()

Обратите внимание, что общий формат uri базы данных:

>> dialect+driver://username:password@host:port/database

а затем на основе учетных данных мы использовали «Основное имя пользователя», «Главный пароль» и «Начальное имя базы данных» при создании нашей базы данных в AWS и «конечную точку» для созданной базы данных;

>> postgresql+psycopg2://Master username:Master password@endpoint:5432/Initial database name

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

club.py

Затем давайте создадим таблицу клубов следующим образом:

from sqlalchemy import Column, String, Integer, Date 
from base import Base 
class Club(Base): 
    __tablename__ = ‘clubs’ 
    id = Column(Integer, primary_key=True) 
    club_name = Column(String) 
    club_stadium = Column(String) 
    date_founded = Column(Date) 
    def __init__(self, club_name, club_stadium, year_founded):
        self.club_name = club_name 
        self.club_stadium = club_stadium 
        self.year_founded = year_founded

Он наследуется от базового класса для создания таблицы клубов. В этой таблице четыре столбца;

  • первичный ключ
  • название клуба
  • название стадиона клуба
  • дата основания клуба

Обратите внимание, что мы используем типы данных Python (Integer, String, Date и т. Д.), Которые SQLAlchemy сопоставляет с наиболее подходящим типом столбца базы данных в зависимости от целевого механизма базы данных.

player.py

Затем давайте создадим таблицу игроков следующим образом:

from sqlalchemy import Column, String, Integer, Date, Table, ForeignKey 
from sqlalchemy.orm import relationship 
from base import Base 
class Player(Base): 
    __tablename__ = 'players' 
    
    id = Column(Integer, primary_key=True) 
    player_name = Column(String) 
    player_number = Column(Integer) 
    club_id = Column(Integer, ForeignKey('clubs.id')) 
    club = relationship('Club', backref='players') 
    def __init__(self, player_name, player_number, club):
        self.player_name = player_name 
        self.player_number = player_number 
        self.club = club

Таблица игроков также имеет четыре столбца;

  • первичный ключ
  • имя игрока
  • номер футболки игрока
  • информация о клубе, за который играет игрок, наследуется из таблицы клубов.

Переменная «club» - это не столбец, а то, что определяет отношения между игроками и таблицей клубов.

update.py

Пришло время создать схему нашей базы данных и вставить в нее некоторые данные. Это делается следующим образом;

from player import Player 
from base import Session, engine, Base 
from club import Club 
from datetime import date 
#create database schema 
Base.metadata.create_all(engine) 
#create a new session 
session = Session() 
#create clubs 
manchester_united = Club('Manchester United', 'Old Trafford', date(1878, 1, 1)) 
chelsea = Club('Chelsea', 'Stamford Bridge', date(1905, 3, 10))
juventus = Club('Juventus', 'Allianz Stadium', date(1897, 11, 1)) 
#create players de_gea = Player('David de Gea', 1, manchester_united) 
pogba = Player('Paul Pogba', 6, manchester_united) 
kante = Player("N'Golo Kante", 7, chelsea) 
ronaldo = Player('Cristiano Ronaldo dos Santos', 7, juventus) 
#persist the data 
session.add(manchester_united) 
session.add(chelsea) 
session.add(juventus) 
session.add(de_gea) 
session.add(pogba) 
session.add(kante) 
session.add(ronaldo) 
#commit and close session 
session.commit() 
session.close()

Сначала мы создали схему базы данных, а затем сеанс, который будет использоваться для сохранения данных. Затем мы создали несколько объектов клуба и игрока, которые будут преобразованы в строки данных в таблицах клубов и игроков соответственно. Затем мы сохранили данные и, наконец, зафиксировали данные перед закрытием сеанса. Теперь данные находятся в нашей базе данных.

query.py

Наконец, давайте запросим нашу базу данных, чтобы убедиться, что данные, которые мы сохранили в последнем разделе, действительно были сохранены. Это достигается с помощью следующего кода;

from club import Club 
from base import Session 
from player import Player 
#creates a session 
session = Session() 
#extracts all the players 
players = session.query(Player).all() 
for player in players: 
    print(f’{player.player_name} plays for {player.club.club_name} and wears shirt number {player.player_number}’)

Результат этого будет следующим:

David de Gea plays for Manchester United and wears shirt number 1 Paul Pogba plays for Manchester United and wears shirt number 6 N'Golo Kante plays for Chelsea and wears shirt number 7 Cristiano Ronaldo dos Santos plays for Juventus and wears shirt number 7

СЛАДКИЙ!!!

НАКОНЕЦ-ТО

Спасибо, что пришли, и я надеюсь, что это было полезно. Как и было обещано, для завершения этого примера реализовать другие отношения;

Один на один: новая таблица с информацией об игроках, которые являются самыми результативными игроками клуба за все время. Поскольку в клубе может быть только один лучший бомбардир за всю историю и очень редко когда игрок становится лучшим бомбардиром за всю историю более чем в клубе, то с клубами могут быть установлены индивидуальные отношения. Таблица.

Многие-ко-многим: новая таблица с информацией о спонсорах. Поскольку у клуба может быть больше спонсоров, а спонсор может спонсировать больше, чем клуб, с таблицей клубов могут быть установлены отношения «многие ко многим».