Взаимодействие с базой данных

Последнее обновление: 07.09.2022

Создание сессии базы данных

Для взаимодействия с базой данных необходимо создать сессию базы данных, которая представляет объект sqlalchemy.orm.Session. Через этот объект идет вся работа с БД. Но для этого вначале надо создать класс-построитель Session с помощью функции-фабрики sessionmaker()

from sqlalchemy.orm import sessionmaker

SessionLocal = sessionmaker(autoflush=False, bind=engine)

эта функция принимает ряд параметров, в частности, здесь применяется два параметра

  • autoflush: при значении True (значение по умолчанию) будет автоматически вызываться метод Session.flush(), который записывает все изменения в базу данных

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

Результатом функции является класс SessionLocal. После этого можно создать объект этого класса и через него взаимодействовать в бд:

from sqlalchemy.orm import sessionmaker

SessionLocal = sessionmaker(autoflush=False, bind=engine)
db = SessionLocal()

Здесь db как раз представляет объект Session.

CRUD

Рассмотрим простейшие операции CRUD (Create-Read-Update-Delete).

Добавление данных

Для добавления в базу данных необходимо сначала создать объект модели, который передается в метод add() объекта Session. После добавления для подтверждения изменений у объекта Session вызывается метод commit()

# создаем объект Person для добавления в бд
tom = Person(name="Tom", age=38)
db.add(tom)     # добавляем в бд
db.commit()     # сохраняем изменения

Например, определим файле приложения следующий код:

from sqlalchemy import create_engine
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import sessionmaker, Session
from sqlalchemy import  Column, Integer, String

from fastapi import FastAPI

SQLALCHEMY_DATABASE_URL = "sqlite:///./sql_app.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})

# создаем модель, объекты которой будут храниться в бд
class Base(DeclarativeBase): pass
class Person(Base):
    __tablename__ = "people"

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

# создаем таблицы
Base.metadata.create_all(bind=engine)

# создаем сессию подключения к бд
SessionLocal = sessionmaker(autoflush=False, bind=engine)
db = SessionLocal()

# создаем объект Person для добавления в бд
tom = Person(name="Tom", age=38)
db.add(tom)     # добавляем в бд
db.commit()     # сохраняем изменения

print(tom.id)   # можно получить установленный id

# приложение, которое ничего не делает
app = FastAPI()

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

Добавление данных в БД

Стоит отметить, что в данным случае в классе Person атрибут id выступает в качестве первичного ключа и генерируется в самой бд при добавлении строки в таблицу. Но после добавления объекта мы можем получить значение данного атрибута:

print(tom.id)

Следует отметить, что после добавления или обновления объекта, если мы хотим использовать этот объект, обращаться к его атрибутами, то желательно, а иногда может быть необходимо, использовать метод refresh(), который обновляет состояние объекта:

# создаем объект Person для добавления в бд
tom = Person(name="Tom", age=38)
db.add(tom)     # добавляем в бд
db.commit()     # сохраняем изменения
db.refresh(tom)  # обновляем состояние объекта
print(tom.id)   # можно получить установленный id

Подобным образом можно добавить несколько объектов:

bob = Person(name="Bob", age=42)
sam = Person(name="Sam", age=25)
db.add(bob)
db.add(sam)
db.commit()

Причем метод commit() вызывается только один раз.

Однако есть надо добавить несколько объектов, то проще применить метод add_all(), который добавляет список объектов:

alice = Person(name="Alice", age=33)
kate = Person(name="Kate", age=28)
db.add_all([alice, kate])
db.commit()

Получение данных

Для получения объектов из базы данных вначале у объекта Session необходимо вызывать метод query() - в него передается тип модели, данные которой необходимо получить:

db.query(Person)

Но данный метод просто создает объект Query - некоторый запрос, который будет выполнен в будущем при непосредственном получении данных. Далее применяя к объекту Query различные методы, мы можем получить непосредственный результат. Например, если надо получить все объекты, применяется метод all():

people = db.query(Person).all()

Метод all возращает список объектов модели. Полный код:

from sqlalchemy import create_engine
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import sessionmaker
from sqlalchemy import  Column, Integer, String

from fastapi import FastAPI

SQLALCHEMY_DATABASE_URL = "sqlite:///./sql_app.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})


class Base(DeclarativeBase): pass
class Person(Base):
    __tablename__ = "people"

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

SessionLocal = sessionmaker(autoflush=False, bind=engine)
db = SessionLocal()

# получение всех объектов
people = db.query(Person).all()
for p in people:
    print(f"{p.id}.{p.name} ({p.age})")

# приложение, которое ничего не делает
app = FastAPI()
Получение данных из базы данных через SQLAlchemy в FastAPI и Python

Для получения одного объекта по id применяется метод get() класса Session. В качестве параметров метод получает тип модели и идентификатор объекта, который надо получить. Например, получим один объект Person, у которого id = 1:

# получение одного объекта по id
first_person = db.get(Person, 1)
print(f"{first_person.name} - {first_person.age}")  
# Tom - 38

Для фильтрации у объекта Query применяется метод filter(), который принимает условие фильтрации. Например:

people = db.query(Person).filter(Person.age > 30).all()
for p in people:
    print(f"{p.id}.{p.name} ({p.age})")

Здесь получаем все объекты Person, у которых значение атрибута age более 30. Метод filter() также возвращает объект Query, поэтому для получения собственно списка объектов, которые соответствуют фильтру, в конце по цепочке применяется метод all()

Для получения только одного объекта применяется метод first() класса Query:

first = db.query(Person).filter(Person.id==1).first()
print(f"{first.name} ({first.age})")

В данном случае получаем объект Person, у которого id = 1.

Стоит отметить, что методы get() и first() возвращают None, если объект не найден. Поэтому при получении одиночного объекта желательно проверять его на значение None.

Обновление

Для обновления объекта достаточно изменить значения его атрибутов и затем вызвать у объекта Session метод commit() для применения изменений:

# получаем один объект, у которого имя - Tom
tom = db.query(Person).filter(Person.id==1).first()
print(f"{tom.id}.{tom.name} ({tom.age})")   
# 1.Tom (38)

# изменениям значения
tom.name = "Tomas"
tom.age = 22

db.commit() # сохраняем изменения

# проверяем, что изменения применены в бд - получаем один объект, у которого имя - Tomas
tomas = db.query(Person).filter(Person.id == 1).first()
print(f"{tomas.id}.{tomas.name} ({tomas.age})")    
# 1.Tomas (22)

Удаление

Для удаления у объекта Session применяется метод delete(), в который передается удаляемый объект:

bob = db.query(Person).filter(Person.id==2).first()
db.delete(bob)  # удаляем объект
db.commit()     # сохраняем изменения
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850