Основы ORM SQLAlchemy

Работа с SQLALchemy сопряжена с большим количеством моментов. В частности, необходимо научиться добавлять данные, обновлять их, удалять и совершать ряд других операций. Сегодня раскроем то, как это делать правильно.

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

Для создания новой записи с использованием SQLAlchemy, необходимо сделать следующее:

  1. Создать объект. 
  2. Добавить объект в сессию.
  3. Загрузить сессию.

Сессия – это основной инструмент взаимодействия с базой данных SQLAlchemy. При этом ее создание осуществляется автоматически. Все, что нужно пользователю – это наладить работу с Flask-SQLAlchemy. Чтобы получить доступ к объекту используется db.session. Он используется для работы с базой данных. И он же необходим для осуществления транзакции. 

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

(env) gvido@vm:~/flask_app$ python main2.py shell

>>>

>>> from main2 import db, Post, Tag, Category

>>>

>>>

>>>  c1 = Category(name='Python',  slug='python')

>>>  c2 = Category(name='Java',  slug='java')

>>>

Этот пример кода демонстрирует, как создавать объекты Category. Чтобы работать с отдельными их атрибутами, используется точка.  

>>>

>>> c1.name, c1.slug

('Python', 'python')

>>>

>>> c2.name, c2.slug

('Java', 'java')

>>>

Затем происходит добавление объектов в сессию.

>>>

>>> db.session.add(c1)

>>> db.session.add(c2)

>>>

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

>>>

>>> print(c1.id)

None

>>>

>>> print(c2.id)

None

>>>

Для каждого объекта значение атрибута idNone. Это означает, что в базе данных они не сохраняются. 

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

>>>

>>> db.session.add_all([c1, c1])

>>>

Можно даже попробовать добавить объект несколько раз в ту же сессию. При этом никаких исключений не возникает. 

Чтобы ознакомиться с перечнем объектов сессии, используется db.session.new

>>>

>>> db.session.new

IdentitySet([<None:Python>, <None:java>])

>>>

Хорошо, а что делать, когда надо сохранить объект в базе данных? Для этого используется метод commit()

>>>

>>> db.session.commit()

>>>

Значением атрибута id объекта Category в данной ситуации будет выступать первичный ключ, а не None.  

>>>

>>> print(c1.id)

1

>>>

>>> print(c2.id)

2

>>>

Таблица с категориями будет иметь приблизительно следующий вид.Основы ORM SQLAlchemy

При этом нет связи новых категорий с постами. Следовательно, c1.posts и c2.posts возвращают список без каких-либо данных в данной ситуации. 

>>>

>>> c1.posts

[]

>>>

>>> c2.posts

[]

>>>

Теперь попытаемся создать несколько постов.

>>>

>>> p1 = Post(title='Post 1', slug='post-1',  content='Post 1', category=c1)

>>> p2 = Post(title='Post 2', slug='post-2',  content='Post 2', category=c1)

>>> p3 = Post(title='Post 3', slug='post-3',  content='Post 3', category=c2)

>>>

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

>>> p1.category = c1

Затем в сессию добавляются объекты и делается коммит. 

>>>

>>> db.session.add_all([p1,  p2,  p3])

>>> db.session.commit()

>>>

И в этом случае атрибут posts вернут список, в котором уже будут содержаться значения. 

>>>

>>> c1.posts

[<1:Post 1>, <2:Post 2>]

>>>

>>> c2.posts

[<3:Post 3>]

>>>

Вместе с тем, возможно получение доступа к объекту Category, к которому относится пост, с использованием специального атрибута category объекта Post

>>>

>>> p1.category

<1:Python>

>>>

>>> p2.category

<1:Python>

>>>

>>> p3.category

<2:Java>

>>>

Необходимо учитывать то, что все это делается с помощью инструкции relationship() в модели Category. На данный момент в базе данных есть три поста, но с тегами нет связи ни у одного из них. 

>>>

>>> p1.tags, p2.tags, p3.tags

([], [], [])

>>>

 А чтобы создать теги, необходимо написать код, подобный этому. 

>>>

>>> t1 = Tag(name="refactoring", slug="refactoring")

>>> t2 = Tag(name="snippet", slug="snippet")

>>> t3 = Tag(name="analytics", slug="analytics")

>>>

>>> db.session.add_all([t1, t2, t3])

>>> db.session.commit()

>>>

С помощью этого кода выполняется создание трех объектов тегов и делается их коммит в базу данных. Но все еще отсутствует привязка постов к ним. Чтобы их связать, необходимо написать адаптировать под свои задачи следующий код. 

>>>

>>> p1.tags.append(t1)

>>> p1.tags.extend([t2, t3])

>>> p2.tags.append(t2)

>>> p3.tags.append(t3)

>>>

>>> db.session.add_all([p1, p2, p3])

>>>

>>> db.session.commit()

>>>

С помощью этого коммита мы добавили пять записей в таблицу.Основы ORM SQLAlchemy

Теперь посты связываются с определенным количеством тегов. 

>>>

>>> p1.tags

[<1:refactoring>, <2:snippet>, <3:analytics>]

>>>

>>> p2.tags

[<2:snippet>]

>>>

>>> p3.tags

[<3:analytics>]

>>>

Также можно получить доступ к постам, относящимся в определенному тегу. 

>>>

>>> t1.posts

[<1:Post 1>]

>>>

>>> t2.posts

[<1:Post 1>, <2:Post 2>]

>>>

>>> t3.posts

[<1:Post 1>, <3:Post 3>]

>>>

>>>

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

>>>

>>> t1 = Tag(name="refactoring", slug="refactoring")

>>> t2 = Tag(name="snippet", slug="snippet")

>>> t3 = Tag(name="analytics", slug="analytics")

>>>

>>> p1.tags.append(t1)

>>> p1.tags.extend([t2, t3])

>>> p2.tags.append(t2)

>>> p3.tags.append(t3)

>>>

>>> db.session.add(p1)

>>> db.session.add(p2)

>>> db.session.add(p3)

>>>

>>> db.session.commit()

>>>

Также обратите внимание на строки 11-13. Здесь в сессию добавляются объекты Post. Они связаны с тегами таким образом, что добавление поста в сессию приводит к добавлению тегов, которые связанные с ним. Тем не менее, можно добавить их и вручную. Исключения это не вызовет.

Обновление данные

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

>>>

>>> p1.content # начальное значение

'Post 1'

>>>

>>> p1.content = "This is content for post 1"  # задаем новое значение

>>> db.session.add(p1)

>>>

>>> db.session.commit()

>>>

>>> p1.content  # обновленное значение

'This is content for post 1'

>>>

Видим, что здесь мы сначала передали атрибуту объекта новое значение, затем добавили объект и сделали коммит. 

Удаление данных

Для выполнения этой задачи используется метод delete() объекта сессии. Ему необходимо передать объект, а далее при последующем коммите будут убраны те данные, которые ему были переданы.

Давайте попробуем создать тег seo, связанный с постами p1 и p2. Его мы потом будем удалять.  

 >>>

>>> tmp = Tag(name='seo', slug='seo')  # создание временного объекта Tag

>>>

>>> p1.tags.append(tmp)

>>> p2.tags.append(tmp)

>>>

>>> db.session.add_all([p1, p2])

>>> db.session.commit()

>>>

Этот код выполняет следующие действия:

  1. Добавляет строку в таблицу table
  2. Две строки добавляются в таблицу post_tags.

После этого база данных будет обновлена следующим образом.Основы ORM SQLAlchemy

Основы ORM SQLAlchemy

А теперь давайте удалим наш временный тег. 

>>>

>>> db.session.delete(tmp)

>>> db.session.commit()

>>>

После того, как выполнится этот коммит, все строки, добавленные в предыдущем фрагменте кода, будут удалены. При этом пост, с которым тег был связан, удаляться не будет.

Во время удаления объекта значение связанного с ним объекта в дочерней таблице становится NULL. Чтобы этот момент продемонстрировать наглядно, приведем фрагмент кода. 

>>>

>>> c4 = Category(name='css', slug='css')

>>> p4 = Post(title='Post 4', slug='post-4', content='Post 4', category=c4)

>>>

>>> db.session.add(c4)

>>>

>>> db.session.new

IdentitySet([<None:css>, <None:Post 4>])

>>>

>>> db.session.commit()

>>>

Этим коммитом добавляется две дополнительные строки, по одной в каждую таблицу. Одна добавляется в categories, а другая – в posts.

Запрос данных

Для запуска запроса к базе данных, необходимо воспользоваться методом query() объекта session. С помощью этого метода программа получает объект flask_sqlalchemy.BaseQuery, который используется для выполнения запросов к базе. 

Основные методы этого класса приводятся в данной таблице:

Метод Описание
all() Возвращает результат запроса (представленный flask_sqlalchemy.BaseQuery) в виде списка.
count() Возвращает количество записей в запросе.
first() Возвращает первый результат запроса или None, если в нем нет строк.
first_or_404() Возвращает первый результат запроса или ошибку 404, если в нем нет строк.
get(pk) Возвращает объект, который соответствует данному первичному ключу или None, если объект не найден.
get_or_404(pk) Возвращает объект, который соответствует данному первичному ключу или ошибку 404, если объект не найден.
filter(*criterion) Возвращает новый экземпляр flask_sqlalchemy.BaseQuery с оператором WHERE.
limit(limit) Возвращает новый экземпляр flask_sqlalchemy.BaseQuery с оператором LIMIT.
offset(offset) Возвращает новый экземпляр flask_sqlalchemy.BaseQuery с оператором OFFSET.
order_by(*criterion) Возвращает новый экземпляр flask_sqlalchemy.BaseQuery с оператором OFFSET.
join() Возвращает новый экземпляр flask_sqlalchemy.BaseQuery после создания SQL JOIN.

Выводы

Мы разобрали основные аспекты, которые касаются ORM SQLAlchemy. Конечно, это далеко не все. Работа с базами данных – отдельная наука. Но этих основ достаточно для того, чтобы получить базовые представления о том, как налаживается взаимодействие с ними.

ОфисГуру
Adblock
detector