Как работать с postgresql через python
Перейти к содержимому

Как работать с postgresql через python

  • автор:

Создаём свою БД на PostgreSQL из CSV

Kaggle — — платформа созданная для проведение конкурсов по исследованию данных. Организаторы выкладывают Datasets , описывают задачи , метрики по которым будут выявляться победители конкурса , призы и время проведения. Каждый желающий может выставить свою работа по этим данных , красиво описать её , показать свои умения и надеяться на победу.

Мы будем использовать Used Cars Dataset

Также мы можем посмотреть Code других участников соревнования

  • подчерпнуть оттуда интересную информацию
  • найти нестандартные подходы к обработке данных
  • На примере других работа , научиться чему-то новому
  • и даже наткнуться на боже зачем это тут ? интересную работу по »Ускорение рабочего процесса Pandas с Modin»
  • Найти друзей
  • Заставить других сделать свою работу
  • Узнать ответ на интересующий тебя вопрос(есть шанс)

Перейдём к делу, Pgadmin4

pgAdmin — это платформа с открытым исходным кодом для администрирования и разработки на PostgreSQL и связанных с ней систем управления базами данных.

pgAdmin будет предложен в установке PostgreSQL, я пользуюсь 14.3. Багов и проблем не боюсь , беру самую новую версию сразу видно профессионал. Если боитесь устанавливать приложение без ведения за ручку , вам поможет интернет()_(). Уже 1000 раз было рассказывать как это делать и что за чему , так что не буду тратить наше драгоценное.

Перейдём к делу 2, Python

Python — — высокоуровневый язык программирования. и нам нужна библиотека pandas

Перейдём к делу 3, Pycharm

Pycharm — — среда разработки(IDE) созданная специально для языка программирования Python.

  • Предоставляет средства для анализа кода
  • графический отладчик
  • инструменты для отладки юнит-тестов
  • интуитивно понятный интерфейс
  • очень много полезных функций для продвинутых пользователей

Начнём кодить(0)_(з)

экспорт данных + получение основной информации

для начала открываем Pycharm, создаём там новый проект и в терминале инсталлируем библиотеку pаndas Открываем терминал и пишем там pip install pandas, нажимаем enter и ждём установки.

pip install pandas

Далее нам надо открыть для чтения наш файл —

import pandas as pd # загружаем наш csv car = pd.read_csv(r'C:\Users\ratmu\PycharmProjects\Cars\vehicles.csv') # просмотр первыйх 5 строк print(car.head(5)) 

видим что из-за 26 столбцов, Pycharm не подгружает всё таблицу( в дальнейшем исправим)

# Cведения о датафрейме, выходит общая информация о нём вроде заголовка, количества значений, типов данных столбцов. print(car.info())

Получаем основные данные из таблицы.

  • Название всех столбцов
  • Количество значений в них
  • Типы данных
# загружаем нашу csv , смотрим тольна на первые 100 строк ибо долго грузиться полный файл ) car = pd.read_csv(r'C:\Users\ratmu\PycharmProjects\Cars\vehicles.csv',nrows=100) # просмотр всей таблици без ограничений колличество знаков , на строку) print(car.to_csv(None))

Получаем гигантский DF который я не могу передать как картинку , так что переходим сразу обработке этих данных

Очистка данных

Убирает лишние столбцы

Нам точно не нужны url ссылки, и пустая строка country , так же нам не надо описание автомобиля на 1000+ символов(description) Так что пишемс простой код

import pandas as pd # загружаем нашу csv car = pd.read_csv(r'C:\Users\ratmu\PycharmProjects\Cars\vehicles.csv') # удлаляем столбци с которыми не будем работать car.drop(['description', 'county', 'url', 'region_url', 'image_url', 'posting_date'], axis=1, inplace=True)

drop удаления столбцов , Axis: указывает, что столбцы или строки должны быть удалены, inplace = True, он возвращает Data Frame с удаленными столбцами или None

После этого сохраняем наш изменённый df в новый файл , что бы в дальнейшем работать только с нужными данными

# сохраняем обработанный df в csv файл car.to_csv('car_info.csv')

Убираем выбросы

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

Нас интересуют выбросы в колонке price, согласитесь если цена на машину будет 5 000 000 000 долларов это будет сильно менять среднее значение цены и мешать нашим вычислениям

Находим выбросы

Узнаем самые часто встречаемые цены с помощью value_counts И_И узнаем статистику по цене в нашем df с помощью describe

print(car['price'].value_counts().iloc[:5]) print(car.price.describe())

слева видим что у нас есть 32к значений = 0, которые стоят обрезать , и множество значений цены = около 3к

справа у нас показатели зашкаливают и выдают огромные цифры. ЧТО ТО ТУТ НЕ ТАК.

А теперь сделаем грубую и ужасную профессиональную вырезку. Я называю её «и так сойдёт»(объясняю, мы как бы не готовим данные для отчётов и т.д , а просто убираем самый явный бред)

Импортируем 2 крутые штуки seaborn

pip install seaborn pip install matplotlib

Теперь в шапку нашего кода добавляем

import matplotlib.pyplot as plt import seaborn as sns

Строем простецкий графии

plt.figure(figsize=(5,8)) sns.boxplot(y='price', data=car,showfliers=True) plt.show()

Тут мы смотря на значения Y будем постепенно обрезать наши выбросы , пока они не станут чуть-чуть адекватными( код ниже)

Убираем выбросы
# price > 300000 если труе обрезаем ( а эту цифру берём из значение Y с графика выше) car.drop(car[car.price > 300000].index, inplace = True) # + убираем все лишнии значения car.drop(car[car.price == 0].index, inplace = True)

да это всё можно делать с помощью IQR (но это совершенно другая история)

И с помощью value_counts, describe проверяем похоже ли это на правду

Сохраняем то что сделали

# сохраняем обработанный df в csv файл без заголовка и интекса , для экспорта в pgadmin car.to_csv('car_info.csv', index=False)

Переноcим данные в СУБД

Создаём пустую бд под экспорт

Осталось дело за малым, открываем pgAdmin4(и подключаемся к серверу)

Далее нам нужно, создать базу данных

Выбираем нашу базу данных и открываем запросник

Вводим туда простейший код

CREATE TABLE car ( car_id int8, region text, price int8, year float4, manufacture text, model text, condition_car text, cylinders text, fuel text, odometer float4, tittle_status text, transmision text, VIN text, drive text, size text, type text, paint_color text, state text, lat float4, long float4 )

дааааааа — можно использовать CHARACTER VARYING , int4 , date . Но мы сейчас не про экономию места на диске

Далее нам надо импортировать наши данные в таблицу

Занимаемся экспортом данных

Находим и открываем sql Shell (psql) — терминальный интерфейс для PostgreSQL

просто нажимаем на enter везде кроме, Database(название вашей базы данных) и Пароль пользователя postgres. И у нас начинается подключение

Далее вводим команду

\COPY car FROM 'C:\Users\ratmu\PycharmProjects\Cars\vehicles.csv' DELIMITER ',' CSV HEADER;

и бежим проверять в pgAdmin всё ли сработало

SELECT * FROM car

Если увидели таблицу значит вы молодец

PostgreSQL

Одной из наиболее популярных реляционных систем баз данных является PostgreSQL. Рассмотрим, как работать с базами данных PostgreSQL в приложении на языке Python.

Перед началом работы естественно должна быть установлена сама PostgreSQL. Про установку PostgreSQL можно прочитать в соответствующей статье Установка сервера PostgreSQL.

Стандартные библиотеки Python не предоставляют встроенного функционала для работы с PostgreSQL, однако есть большое количество сторонних библиотек. Наиболее популярной из них является Psycopg 2 (официальный сайт Psycopg). Данная библиотека реализована на языке C, благодаря чему обладает сравнительно большой производительностью.

Установка psycopg

Для установки выполним в терминале следующую команду:

pip install psycopg2

После этого мы можем импортировать библиотеку в программе на Python:

import psycopg2

Подключение к серверу PostgreSQL

Для подключения к серверу PostgreSQL применяется функция connect() . Она принимает настройки подключения:

psycopg2.connect(dbname="db_name", host="db_host", user="db_user", password="db_pass", port="db_port")

Функция принимает следующие параметры:

  • dbname : имя базы данных
  • user : имя пользователя
  • password : пароль пользователя
  • host : хост/адрес сервера
  • port : порт (если не указано, то используется порт по умолчанию — 5432)

При удачном подключении функция connect создает новую сессию базы данных и возвращает объект connection

Класс connection предоставляет ряд методов для работы с подключением к БД:

  • close() : закрывает подключение
  • cursor() : возвращает объект cursor для осуществления запросов к бд
  • commit() : поддверждает транзакцию
  • rollback() : откатывает транзакцию

Например, покдлючимся к стандартной базе данных «postgres» на локальном сервере PostgreSQL:

import psycopg2 conn = psycopg2.connect(dbname="postgres", user="postgres", password="123456", host="127.0.0.1", port="5432") print("Подключение установлено") conn.close()

В данном случае подключение идет для встроенного пользователя по умолчанию «postgres».

Курсор и операции с данными

Метод cursor() объекта connection возвращает курсор — объект cursor , через который можно отправлять запросы к базе данных. Для этого класс cursor предоставляет ряд методов:

  • execute(query, vars=None) : выполняет одну SQL-инструкцию. Через второй параметр в код SQL можно передать набор параметров в виде списка или словаря
  • executemany(query, vars_list) : выполняет параметризованное SQL-инструкцию. Через второй параметр принимает наборы значений, которые передаются в выполняемый код SQL.
  • callproc(procname[, parameters]) : выполняет хранимую функцию. Через второй параметр можно передать набор параметров в виде списка или словаря
  • mogrify(operation[, parameters]) : возвращает код запроса SQL после привязки параметров
  • fetchone() : возвращает следующую строку из полученного из БД набора строк в виде кортежа. Если строк в наборе нет, то возвращает None
  • fetchmany([size=cursor.arraysize]) : возвращает набор строк в виде списка. количество возвращаемых строк передается через параметр. Если больше строк нет в наборе, то возвращается пустой список.
  • fetchall() : возвращает все (оставшиеся) строки в виде списка. При отсутствии строк возвращается пустой список.
  • scroll(value[, mode=’relative’]) : перемещает курсор в наборе на позицию value в соответствии с режимом mode.
import psycopg2 conn = psycopg2.connect(dbname="postgres", user="postgres", password="123456", host="127.0.0.1") cursor = conn.cursor() cursor.close() # закрываем курсор conn.close() # закрываем подключение

Закрытие подключения и курсора

Стоит отметить, что оба объекта — connection и cursor могут использоваться как менеджеры контекста. То есть с помощью выражения with определить контекста. Однако если объект cursor по завершению закрывается, то объект connection НЕ закрывается:

import psycopg2 conn = psycopg2.connect(dbname="postgres", user="postgres", password="123456", host="127.0.0.1", port="5432") with conn: with conn.cursor() as cursor: print("Подключение установлено") print(cursor.closed) # True - курсор закрыт # cursor.close() # нет смысла - объект cursor уже закрыт conn.close() # объект conn не закрыт, надо закрывать

Модель выполнения запросов

Перед выполнением первой команды SQL автоматически создается транзакция, в процессе которой можно выполнять различные выражения SQL с помощью методов execute/executemany курсора, но для подтверждения их выполнения необходимо вызывать метод commit() объекта connection. Условно это может выглядеть так:

import psycopg2 conn = psycopg2.connect(dbname="postgres", user="postgres", password="123456", host="127.0.0.1") cursor = conn.cursor() cursor.execute(sql1) conn.commit() # реальное выполнение команд sql1 cursor.close() conn.close()

Здесь реальное выполнение условной команды sql1 производится только при выполнении метода conn.commit() . Если же надо, чтобы выражения sql автоматически выполнялись при каждом вызове метода cursor.execute() , то можно установить автокоммит с помощью свойства connection.autocommit :

import psycopg2 conn = psycopg2.connect(dbname="postgres", user="postgres", password="123456", host="127.0.0.1") conn.autocommit = True # устанавливаем актокоммит cursor = conn.cursor() cursor.execute(sql1) # непосредственное выполнение команды sql1 cursor.close() conn.close()

Работа с PostgreSQL в Python

17 Ноя. 2018 , Python, 261940 просмотров, How to Work with PostgreSQL in Python

PostgreSQL, пожалуй, это самая продвинутая реляционная база данных в мире Open Source Software. По своим функциональным возможностям она не уступает коммерческой БД Oracle и на голову выше собрата MySQL.

Если вы создаёте на Python веб-приложения, то вам не избежать работы с БД. В Python самой популярной библиотекой для работы с PostgreSQL является psycopg2. Эта библиотека написана на Си на основе libpq.

Установка

Тут всё просто, выполняем команду:

pip install psycopg2

Для тех, кто не хочет ставить пакет прямо в системный python, советую использовать pyenv для отдельного окружения. В Unix системах установка psycopg2 потребует наличия вспомогательных библиотек (libpq, libssl) и компилятора. Чтобы избежать сборки, используйте готовый билд:

pip install psycopg2-binary 

Но для production среды разработчики библиотеки рекомендуют собирать библиотеку из исходников.

Начало работы

Для выполнения запроса к базе, необходимо с ней соединиться и получить курсор:

import psycopg2 conn = psycopg2.connect(dbname='database', user='db_user', password='mypassword', host='localhost') cursor = conn.cursor() 

Через курсор происходит дальнейшее общение в базой.

cursor.execute('SELECT * FROM airport LIMIT 10') records = cursor.fetchall() . cursor.close() conn.close() 

После выполнения запроса, получить результат можно несколькими способами:

  • cursor.fetchone() — возвращает 1 строку
  • cursor.fetchall() — возвращает список всех строк
  • cursor.fetchmany(size=5) — возвращает заданное количество строк

Также курсор является итерируемым объектом, поэтому можно так:

for row in cursor: print(row) 

Хорошей практикой при работе с БД является закрытие курсора и соединения. Чтобы не делать это самому, можно воспользоваться контекстным менеджером:

 from contextlib import closing with closing(psycopg2.connect(. )) as conn: with conn.cursor() as cursor: cursor.execute('SELECT * FROM airport LIMIT 5') for row in cursor: print(row) 

По умолчанию результат приходит в виде кортежа. Кортеж неудобен тем, что доступ происходит по индексу (изменить это можно, если использовать NamedTupleCursor ). Если хотите работать со словарём, то при вызове .cursor передайте аргумент cursor_factory :

from psycopg2.extras import DictCursor with psycopg2.connect(. ) as conn: with conn.cursor(cursor_factory=DictCursor) as cursor: . 

Формирование запросов

Зачастую в БД выполняются запросы, сформированные динамически. Psycopg2 прекрасно справляется с этой работой, а также берёт на себя ответственность за безопасную обработку строк во избежание атак типа SQL Injection:

cursor.execute('SELECT * FROM airport WHERE city_code = %s', ('ALA', )) for row in cursor: print(row) 

Метод execute вторым аргументом принимает коллекцию (кортеж, список и т.д.) или словарь. При формировании запроса необходимо помнить, что:

  • Плейсхолдеры в строке запроса должны быть %s , даже если тип передаваемого значения отличается от строки, всю работу берёт на себя psycopg2.
  • Не нужно обрамлять строки в одинарные кавычки.
  • Если в запросе присутствует знак %, то его необходимо писать как %%.

Именованные аргументы можно писать так:

>>> cursor.execute('SELECT * FROM engine_airport WHERE city_code = %(city_code)s', ) . 

Модуль psycopg2.sql

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

>>> cursor.execute('SELECT * FROM %s WHERE city_code = %s', ('airport', 'ALA')) psycopg2.ProgrammingError: ОШИБКА: ошибка синтаксиса (примерное положение: "'airport'") LINE 1: SELECT * FROM 'airport' WHERE city_code = 'ALA' 

Это можно обойти, если сформировать запрос без участия psycopg2, но есть высокая вероятность оставить брешь (привет, SQL Injection!). Чтобы обезопасить строку, воспользуйтесь функцией psycopg2.extensions.quote_ident , но и про неё легко забыть.

from psycopg2 import sql . >>> with conn.cursor() as cursor: columns = ('country_name_ru', 'airport_name_ru', 'city_code') stmt = sql.SQL('SELECT <> FROM <> LIMIT 5').format( sql.SQL(',').join(map(sql.Identifier, columns)), sql.Identifier('airport') ) cursor.execute(stmt) for row in cursor: print(row) ('Французская Полинезия', 'Матайва', 'MVT') ('Индонезия', 'Матак', 'MWK') ('Сенегал', 'Матам', 'MAX') ('Новая Зеландия', 'Матамата', 'MTA') ('Мексика', 'Матаморос', 'MAM') 

Транзакции

По умолчанию транзакция создаётся до выполнения первого запроса к БД, и все последующие запросы выполняются в контексте этой транзакции. Завершить транзакцию можно несколькими способами:

  • закрыв соединение conn.close()
  • удалив соединение del conn
  • вызвав conn.commit() или conn.rollback()

Старайтесь избегать длительных транзакций, ни к чему хорошему они не приводят. Для ситуаций, когда атомарные операции не нужны, существует свойство autocommit для connection класса. Когда значение равно True , каждый вызов execute будет моментально отражен на стороне БД (например, запись через INSERT).

with conn.cursor() as cursor: conn.autocommit = True values = [ ('ALA', 'Almaty', 'Kazakhstan'), ('TSE', 'Astana', 'Kazakhstan'), ('PDX', 'Portland', 'USA'), ] insert = sql.SQL('INSERT INTO city (code, name, country_name) VALUES <>').format( sql.SQL(',').join(map(sql.Literal, values)) ) cursor.execute(insert) 

Интересные записи:

  • Celery: начинаем правильно
  • Введение в logging на Python
  • Что нового появилось в Django Channels?
  • Работа с MySQL в Python
  • Django Channels: работа с WebSocket и не только
  • FastAPI, asyncio и multiprocessing
  • Почему Python?
  • Pyenv: удобный менеджер версий python
  • Руководство по работе с HTTP в Python. Библиотека requests
  • Обзор Python 3.9
  • Python-RQ: очередь задач на базе Redis
  • Введение в pandas: анализ данных на Python
  • Как написать Telegram бота: практическое руководство
  • Разворачиваем Django приложение в production на примере Telegram бота
  • Авторизация через Telegram в Django и Python
  • Django, RQ и FakeRedis
  • Обзор Python 3.8
  • Итоги первой встречи Python программистов в Алматы
  • Интеграция Trix editor в Django
  • Участие в подкасте TalkPython
  • Строим Data Pipeline на Python и Luigi
  • Видео презентации ETL на Python
  • Авторизация через Telegram в Django приложении

Записки программиста

Мне нравится Python, а также мне нравится PostgreSQL. И вот я подумал — ей, а почему бы не использовать их вместе? 🙂 Для работы с PostgreSQL в мире Python большой популярностью пользуется пакет psycopg2. Но он, по всей видимости, до сих пор не поддерживает prepared statements. Поэтому для своих задач я пока что остановился на чуть менее популярном пакете py-postgresql. Этот пакет, как я понимаю, поддерживает все, что нужно.

Дополнение: Выяснилось, что py-postgresql не работает с последними версиями PostgreSQL. См заметку Работа с PostgreSQL на Python с помощью psycopg2.

Ставится он, как обычно, через pip. Например (но лучше пользоваться virtualenv):

sudo pip3 install py-postgresql

При изучении новой библиотеки сначала я пытаюсь поделать с ней что-нибудь в REPL. Далее я опускаю приглашение REPL’а, которое >>> .

Создание новой сессии:

import postgresql
db = postgresql. open ( ‘pq://postgres:postgres@localhost:5432/mydb’ )

В реальных скриптах, конечно же, не забываем использовать конструкцию with .

Создание схемы, выполнение простых запросов:

db. execute ( «CREATE TABLE users (id SERIAL PRIMARY KEY, »
«login CHAR(64), password CHAR(64))» )

Создание prepared statement и выполнение INSERT-запроса:

ins = db. prepare ( «INSERT INTO users (login, password) VALUES ($1, $2)» )

ins ( «afiskon» , «123» )
# (‘INSERT’, 1)
ins ( «eax» , «456» )
# (‘INSERT’, 1)

Выполнение SELECT-запроса (делаем trim, так как varchar дополняется пробелами):

db. query ( «SELECT id, trim(login), trim(password) FROM users» )
# [(1, ‘afiskon’, ‘123’), (2, ‘eax’, ‘456’)]

К полям можно обращаться как по номерам, так и по именам:

users = db. query ( «SELECT * FROM users WHERE > ) ;

users [ 0 ] [ 0 ]
# 1

users [ 0 ] [ «id» ]
# 1

users [ 0 ] [ «login» ] . strip ( )
# ‘afiskon’

Выполнение UPDATE- и DELETE-запросов:

update = db. prepare ( «UPDATE users SET password = $2 where login = $1» )

update ( «eax» , «789» )
# (‘UPDATE’, 1)

delete = db. prepare ( «DELETE FROM users WHERE > )

delete ( 3 )
# (‘DELETE’, 0)

db. query ( «DELETE FROM users WHERE > )
# (‘DELETE’, 0)

Пример выполнения транзакции:

with db. xact ( ) as xact:
db. query ( «SELECT id FROM users» )
# [(1,), (2,)]

Пример выполнения rollback:

with db. xact ( ) as xact:
db. query ( «SELECT id FROM users» )
xact. rollback ( )

Вызов хранимых процедур:

ver = db. proc ( «version()» )

ver ( )
# ‘PostgreSQL 9.5 . ‘

Работа с курсорами:

db. execute ( «DECLARE my_cursor CURSOR WITH HOLD FOR »
«SELECT id, trim(login) FROM users» )

c = db. cursor_from_id ( «my_cursor» )

c. read ( )
# [(1, ‘afiskon’), (2, ‘eax’)]

Можно ограничить количество считываемых элементов:

c. read ( 100 )

Попробуйте заполнить таблицу таким образом и повторить эксперимент:

for i in range ( 1 , 1000 ) :
ins ( «user» + str ( i ) , «pass» + str ( i ) )

И напоследок рассмотрим наброски типа более гибкой альтернативы pgbench:

import time
import threading
import postgresql

testtime = 10
nthreads = 4

def worker ( ) :
nqueries = 0
with postgresql. open ( ‘pq://eax@192.168.111.222/eax’ ) as db:
query = db. prepare ( «SELECT * FROM themes WHERE > )
starttime = time . time ( )
while time . time ( ) — starttime < testtime:
query ( )
nqueries = nqueries + 1
print ( «Thread » + str ( threading . get_ident ( ) ) + » — total » +
str ( nqueries ) + » queries executed» )

for i in range ( nthreads ) :
t = threading . Thread ( target = worker )
t. start ( )

  • https://pypi.python.org/pypi/py-postgresql;
  • http://pythonhosted.org/py-postgresql/;
  • https://wiki.postgresql.org/wiki/Python;

А как вы нынче работаете с базами данных на Python?

Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *