Postgres - это легендарная база данных. Он существует некоторое время и хорошо зарекомендовал себя при большой поддержке. Эта база данных является быстрой, эффективной и используется широким кругом компаний, от стартапов до международных конгломератов. Одна из причин, по которой Postgres так популярен, заключается в том, что для него существует множество расширений, плагинов и коннекторов. Вы можете подключаться через множество разных языков программирования, и есть также ряд первоклассных ORM.
В зависимости от ваших конкретных потребностей и размера проекта вам может не потребоваться установка тонны дополнительных уровней абстракции или фреймворков для обработки запросов в Postgres. Создание простой оболочки для различных запросов и часто используемых функций несложно и эффективно на таких языках, как Python.
Если вы создаете прототип крошечного приложения или работаете со встроенной системой с жесткими ограничениями, то создание легкой оболочки может оказаться большим преимуществом. Получить результаты JSON из PG очень просто, используя чрезвычайно популярный модуль psycopg2. Этот низкоуровневый модуль подключения к базе данных для Python позволяет подключаться к Postgres, выполнять SQL и другие функции базы данных. Давайте рассмотрим, как настроить оболочку базы данных на Python с помощью этого модуля, чтобы сделать выполнение запросов быстрым и простым.
База данных
В нашем примере сервера Postgres мы собираемся использовать предварительно заполненную базу данных, полную тестовых данных. Это дает нам набор образцов данных для запроса. В конце концов, какое удовольствие - это пустая база данных.
Мы будем использовать Docker для настройки контейнера базы данных, чтобы не загрязнять нашу хост-операционную систему тестовыми установками. Если вы никогда раньше не использовали Docker или нуждаетесь в быстром обновлении, Docker - Руководство для новичков - Часть 1: изображения и контейнеры - отличное руководство от Себастьяна Эшвайлера, которое поможет вам вставай и работай.
Загляните в postgres-dataset на Docker Hub (благодарим aa8y за создание этого невероятно удобного инструмента), чтобы получить последний образ и развернуть его, используя приведенные ниже команды. Вам нужно изменить первый порт с 5432
на другой, если на вашем компьютере уже запущен экземпляр Postgres.
docker pull aa8y/postgres-dataset
docker run -d -p 5432:5432 --name pg-ds-fake aa8y/postgres-dataset:latest
Дайте базе данных несколько минут, чтобы заполнить тестовые данные, а затем присоединитесь к контейнеру, используя следующую команду:
docker exec -it pg-ds-fake /bin/bash
Нам нужно будет сделать одну настройку, чтобы разрешить доступ с хост-машины к экземпляру PG контейнера. При подключении к контейнеру запустите следующее:
echo "host all all 0.0.0.0/0 trust" > /var/lib/postgresql/data/pg_hba.conf pg_ctl reload
Первая строка разрешит все соединения TCP / IP с Postgres и удалит всю остальную аутентификацию. Это строго для тестирования, чтобы упростить работу и не иметь дело с паролями и аутентификацией с хоста. Ни при каких обстоятельствах вы не должны добавлять эту конфигурацию в производственный экземпляр Postgres. Последняя команда перезагружает Postgres, чтобы он принял новую конфигурацию.
Теперь у вас должна быть возможность подключиться к Postgres с помощью psql
с хост-машины, запустив (сначала выйдите из контейнера):
psql -U postgres -h localhost
Если у вас не установлено psql
, вы можете воспользоваться руководством по установке, доступным здесь. Попробуйте выполнить тестовый запрос к базе данных world
:
\c world SELECT * FROM country LIMIT 5;
Обертка
Теперь, когда база данных настроена и работает с некоторыми тестовыми данными, мы можем приступить к настройке нашей оболочки на Python. Давайте откроем новый файл Python и начнем редактирование. Сейчас мы можем просто назвать это wrapper.py
и добавить следующее:
#!/usr/bin/env python3 import simplejson as json import psycopg2 from psycopg2.extras import RealDictCursor class PostgresWrapper: def __init__(self, **args): self.user = args.get('user', 'postgres') self.port = args.get('port', 5432) self.dbname = args.get('dbname', 'world') self.host = args.get('host', 'localhost') self.connection = None
Во-первых, мы используем simplejson
вместо стандартной json
библиотеки, потому что, когда мы запрашиваем Decimal
значения, они будут корректно сериализованы только с использованием более обновленной библиотеки с поддержкой сброса этого типа данных.
Затем мы добавляем библиотеку psycopg2
и фабрику RealDictCursor
. Эта фабрика позволит нам легко сериализовать результаты запроса непосредственно в тип Dict
, а затем впоследствии выгружать его в JSON. Мы также определим базовый класс PostgresWrapper
для хранения всех наших функций и предоставления некоторых значений инициализации по умолчанию. Теперь давайте добавим несколько простых функций подключения:
def connect(self): pg_conn = psycopg2.connect( user=self.user, port=self.port, dbname=self.dbname, host=self.host ) self.connection = pg_conn def get_json_cursor(self): return self.connection.cursor(cursor_factory=RealDictCursor)
Внутри функции connect()
мы используем psycopg2
для прямого подключения к базе данных Postgres, которую мы настроили ранее. Это соединение также указывает, к какой базе данных подключаться внутри Postgres. В этом примере мы будем использовать world
данные, которые содержат такие вещи, как города и страны. Следующая функция использует предыдущее соединение для установки нового курсора. Курсор похож на интерактивное приглашение psql
, в которое вы вводите операторы SQL, за исключением того, что оно не интерактивно и может управляться программно. Этот курсор также использует спецификацию RealDictCursor
для возврата Dict
типов, которые позже легко возвращаются в виде строки JSON.
Наконец, давайте настроим функции для фактического получения некоторых данных:
@staticmethod def execute_and_fetch(cursor, query): cursor.execute(query) res = cursor.fetchall() cursor.close() return res def get_json_response(self, query): cursor = self.get_json_cursor() response = self.execute_and_fetch(cursor, query) return json.dumps(response) def get_countries(self): query = "SELECT * FROM country LIMIT 2;" print(self.get_json_response(query))
Функция execute_and_fetch()
использует курсор, который мы установили ранее, чтобы выполнить запрос SQL, закрыть соединение курсора и затем вернуть результаты. По завершении действия важно закрыть курсор, поскольку в противном случае каждый вызов execute_and_fetch()
будет создавать экземпляры нескольких курсоров и потреблять больше ресурсов в базе данных. Функция get_json_response()
- это вспомогательная функция, которая обрабатывает создание экземпляра курсора и передает курсор и запрос в execute_and_fetch()
. Впоследствии эта функция возвращает ответ в виде строки JSON.
Функция get_countries()
будет использовать get_json_response()
и передавать запрос для стран. Когда мы вызываем эту функцию, мы получаем последний JSON-объект запрошенных строк из базы данных.
Собираем все вместе
Напомним, как должен выглядеть весь класс-оболочка:
#!/usr/bin/env python3 import simplejson as json import psycopg2 from psycopg2.extras import RealDictCursor class PostgresWrapper: def __init__(self, **args): self.user = args.get('user', 'postgres') self.port = args.get('port', 5432) self.dbname = args.get('dbname', 'world') self.host = args.get('host', 'localhost') self.connection = None def connect(self): pg_conn = psycopg2.connect( user=self.user, port=self.port, dbname=self.dbname, host=self.host ) self.connection = pg_conn def get_json_cursor(self): return self.connection.cursor(cursor_factory=RealDictCursor) @staticmethod def execute_and_fetch(cursor, query): cursor.execute(query) res = cursor.fetchall() cursor.close() return res def get_json_response(self, query): cursor = self.get_json_cursor() response = self.execute_and_fetch(cursor, query) return json.dumps(response) def get_countries(self): query = "SELECT * FROM country LIMIT 2;" print(self.get_json_response(query)) dbconn = PostgresWrapper() dbconn.connect() dbconn.get_countries()
Внизу файла мы создаем экземпляр PostgresWrapper
, подключаемся и затем вызываем get_countries()
для печати некоторых образцов данных JSON.
Вы должны иметь возможность просто запустить файл и получить результаты:
./wrapper.py
Теперь вы должны увидеть вывод JSON, подобный этому:
[{"code": "AFG", "name": "Afghanistan", "continent": "Asia", "region": "Southern and Central Asia", ...}]
Если все работает правильно, вы получите очень простой класс-оболочку для Postgres, который можно настроить для вывода BLOB-объектов JSON различных запросов. Его можно включить в существующее приложение Python или даже использовать в качестве рудиментарного бэкэнда для API. Имейте в виду, что это простой пример класса, вы можете немного расширить этот класс и сделать выполнение запросов еще более гибким.
Сочетая Postgres с мощью Python и отличными модулями, вы можете упростить и абстрагироваться от сложности подключения к базам данных и получения данных из них. Для еще более изысканного и элегантного подхода рассмотрите возможность изучения модуля ORM под названием SQLAlchemy. Это позволяет вам взаимодействовать с результатами базы данных как с реальными объектами Python и писать еще менее специфичный для базы данных код.
Спасибо за внимание! Postgres и Python - брак, заключенный на небесах. Эта оболочка очень легкая и простая в использовании, но ее можно расширить, добавив еще больше функций. Напишите в Twitter о своих приключениях, связанных с Python и Postgres.