Ни для кого не новость, что большинство сегодняшних приложений взаимодействуют с базами данных. Особенно с движками на основе RDBMS (движки DB с поддержкой SQL). Как и любой другой язык программирования, Pyhton также предоставляет как собственные библиотеки для взаимодействия с базами данных, так и от третьих лиц. Как правило, вам нужно прописать запросы SQL для CRUD операций.
Чтобы разобраться с этим, в игру вступает ORM.
Введение в ORM
ORM – это акроним от Object Relational Mapping (Объектно-реляционное отображение). Но что именно оно делает?
Из википедии:
Объектно-реляционное отображение — это технология программирования, которая связывает базы данных с концепциями объектно-ориентированных языков программирования, создавая «виртуальную объектную базу данных». Существуют как проприетарные, так и свободные реализации этой технологии.
Звучит круто, да?
Что такое Peewee?
Peewee (http://docs.peewee-orm.com/en/latest/) – это небольшое ORM, которое в данный момент поддерживает postgresql, mysql и sqlite. Разумеется, это не единственное ORM для разработчиков Python. К примеру, Django предоставляет собственную ORM библиотеку, кроме этого, всегда есть SqlAlchemy. Хорошая сторона Peewee – это то, что он занимает мало места, его легко освоить, и вы можете приступить к работе с приложениями за несколько минут.
Достаточно слов, перейдем к кодам!
Установка Peewee
Как и многие другие библиотеки Python, вы можете установить Peewee при помощи pip:
Настройка базы данных
Как я говорил, Peewee поддерживает ряд движков для работы с базами данных (полный список тут: http://docs.peewee-orm.com/en/latest/peewee/database.html), в данной статье я использую MySQL.
Объект MySQLDatabase создан.
Создание моделей в Peewee
Сейчас я перейду к созданию моделей. В этой статье я использую две таблицы или модели: «Категория» и «Продукт«. Категория может содержать несколько продуктов. Сохраняем как файл models.py
Сначала я создал BaseModel. Это связанно с тем, что Peewee просит вас передать dbhandle в каждый класс Model. Чтобы избежать лишних движений, я просто создал базовый класс и расширил его. Ознакомиться со всеми типами столбцов в таблице можно тут.
Хорошо, наша BaseModel и Category созданы. Модель Category состоит из четырех полей:
- id, который является полем автоматического прироста;
- name содержит имя категории;
- updated_at и created_at – поля timestamp, которые определяют настоящее время по умолчанию.
В классе Meta я передаю название таблицы в собственность db_table. Это не обязательно, если название таблицы и модели одинаковые. Собственность order_by указывает, какой столбец должен использоваться для сортировки данных во время извлечения. Вы можете переписать его, передав вид по полю на ваше усмотрение.
Перед тем как мы двинемся дальше, я хочу создать еще один файл под названием operations.py, в котором я буду использовать эти модели.
После импорта, я подключаюсь к базе данных. Ошибка peewee.OperationalError ссылается на все ошибки, связанные с Peewee. К примеру, если вы введете неправильные учетные данные, вы получите следующее:
Затем мы вызываем Category.create_table(), которые создает таблицу с указанной ранее собственностью. Если вы передаете safe=True в качестве параметра, то существующая таблица просто перепишется. Это может привести к проблемам в реальной ситуации.
Далее, модель Product:
Она аналогична модели Category. Разница только в ForeignKeyField, который указывает, как именно Product должен быть связан с Category. Обновление основы должно выглядеть следующим образом:
После запуска указанного выше кода, создается таблица модели product, а также отношение с таблицей categories. Вот скриншот моего клиента sql:
Вставка записи (INSERT)
Теперь мы можем перейти к добавлению данных сперва в category, а затем в таблицу products. Так как у нас есть рабочие модели, не так просто добавлять или обновлять записи.
Я добавил функцию под названием add_category() с параметром и именем внутри. Объект Category создан, как и поля таблицы, которые являются переданной собственностью данного объекта класса. В нашем случае, это поле name.
The row.save() сохраняет данные из объекта в базу данных.
Круто, не так ли? Больше не нужно прописывать уродливые INSERT-ы.
Теперь добавим product.
add_product берет name, price и category_id в качестве вводных данных. Сначала, я проверю, существует ли категория, если да – значит её объекты хранятся в базе. В ORM вы имеете дело с объектом, по этому вы передаете информацию о категории в качестве объекта, так как мы уже определили эту взаимосвязь ранее.
Далее, я буду создавать разделы в main.py:
Теперь добавим продукты:
Полный main.py можете видеть ниже:
Я передаю имя категории, как только её объект будет найден и передан объекту класса Product. Если вы хотите пойти по пути SQL, для начала вам нужно выполнить SELECT, чтобы получить существующий category_id, и затем назначить id добавляемому продукту.
Так как работать с ORM – значит иметь дело с объектами, мы храним объекты вместо скалярных значений. Кто-то может посчитать это слишком «инженерным» методом в нашем случае, но подумайте о случаях, когда вы понятия не имеете о том, какая база данных должна быть использована в будущем. Ваш код – это универсальный инструмент для работы с базами данных, так что если он работает с MySQL, или MSSQL, то он будет работать даже с MongoDb (гипотетически).
Выбор нескольких записей
Сначала выделяем категории:
Category.select() возвращает ВСЮ запись, которая будет отсортирована по столбцу created_at, что мы и указали в классе Meta.
Теперь выбираем все продукты:
Здесь я перебираю продукты и добавляю запись в список product_data. Обратите внимание на доступ к категории продукта. Больше нет SELECT для получения ID, с последующим поиском названия. Простой цикл делает все за нас. При запуске, информация о продукте будет отображаться следующим образом:
Выбор одной записи
Чтобы выбрать одну запись, вам нужно использовать метод get:
Теперь это называется так:
Название товара передано функции find_product, если запись существует – она вернет экземпляр Product. Здесь я вывожу категорию, связанную с этим продуктом.
Обновление записей в Peewee
Обновление записей – это так же просто, как и их создание. Вы получаете экземпляр объекта, после чего обновляете его.
После этого, вызываем его как:
Удаление записей в Peewee
Удаление записи не сильно отличается от обновления:
Вызываем данную функцию для удаления раздела:
Готовое приложение
Сохраняем данные криптовалют от биржи Binance
Допустим у нас уже есть MySQL база данных и существует таблица: coins. Нам нужно создать модель для этой существующей таблице и сохранить полученные json данные от Binance.
Данные от Binance мы получим по ссылке: https://api.binance.com/api/v1/ticker/24hr для HTTP запроса мы будет использовать библиотеку Requests на примере.
Что мы реализуем в нашем приложении:
- Добавление новых монет;
- Проверка если монета существует;
- Обновления данных по цене если монета существует;
- Сортируем монеты по объему за 24 часа;
- Кол-во монет которые торгуются с BNB в паре (Binance Coin);
- Выбираем случайные 5 монет
Исходный код
В третьей строке вы можете видеть список типов столбцов из таблицы, такие как Integer, Float и Varchar (IntegerField, FloatField, CharField, PrimaryKeyField, TimestampField). Подробнее про тип полей можете узнать из документации: https://peewee.readthedocs.io/en/2.0.2/peewee/fields.html
Больше примеров которые не были использованы: http://docs.peewee-orm.com/en/latest/peewee/querying.html
Результат который я получил:
Меняем MySQL на SQLite
Используя пример из кода выше, мы изменим базу данных из MySQL на SQLite не трогая код (кроме самого подключения). Нам нужно обновить немного наш файл. С самых первых строк было:
Теперь у нас:
После запуска отредактированного кода мы получим ошибку:
Ошибка в примере «Выбираем случайные 5 монет», в коде мы используем fn.Rand() и он работает для MySQL, но для SQLite и PostgreSQL он работать не будет, нужно использовать fn.Random(). Подробнее: http://docs.peewee-orm.com/en/latest/peewee/querying.html#getting-random-records
Вывод
Отлично, вы освоили основы Peewee и то, как вы можете использовать эту маленькую и эффективную ORM в ваших следующих проектах, связанных с Pyhton. Если у вас есть дополнительные вопросы – вы можете ознакомиться с официальной документацией и найти в ней ответы.
После запуска у нас появился файл базы данных binance-coins.db
Интересно? Тогда скорее подписывайся на канал, здесь много такого!