PythonからPostgreSQLに接続する方法【psycopg3対応・初心者向け】

Pythonロゴ風のヘビとPostgreSQLのゾウが向かい合うイラスト

※ この記事は2024年に公開した「psycopg2」版の記事を、現在の標準ライブラリである psycopg3 に対応させて全面リライトしたものです。URLはそのまま引き継いでいます。

PythonからPostgreSQLに接続できるようになると、「ちゃんと動いた」という小さな達成感があります。

この記事では、PythonからPostgreSQLに接続して、データを保存・取得するところまでを、初心者の方にも分かるように順番に解説します。

むずかしい話は後回しです。まずは「つながった」「保存できた」という成功体験を一緒に作っていきましょう。

この記事でできること

  • PythonからPostgreSQLに接続できる
  • テーブルを作って、データを保存・取得できる
  • パスワードをコードに書かない、安全な管理方法が分かる
  • 接続できないときに、エラーメッセージから原因を追える

先に結論
今から始めるなら、ライブラリは psycopg2 ではなく psycopg(第3世代・psycopg3) を選んでください。psycopg2は今もメンテナンスされていますが、新機能の開発はpsycopg3側が中心です。これから書くコードも、すべてpsycopg3で統一します。

この記事はローカル環境での確認をベースにしていますが、コードはあとでVPSなどの環境に移しても、ほぼそのまま使えます。

目次

この記事の前提環境

  • OS:Windows(Mac・Linuxでもコードは同じです)
  • Python:3.12〜3.14
  • PostgreSQL:インストール済みで、起動していること
  • エディタ:VS Code

仮想環境(venv)の作り方がまだあいまいな方は、先に環境構築の記事で整えてから戻ってくると、つまずきにくいです。

→ Anacondaを使わずにWindowsでPython環境を作る方法

psycopg2とpsycopg3、何が違うの?

psycopgは、PythonからPostgreSQLを操作するためのライブラリです。役割をひとことで言うと、「PythonとPostgreSQLをつなぐ橋渡し役」 です。

ややこしいのは名前です。第2世代が「psycopg2」、第3世代が「psycopg」という名前で配布されています。

項目psycopg2(第2世代)psycopg(第3世代)
インストール名psycopg2-binarypsycopg[binary]
importの名前import psycopg2import psycopg
位置づけメンテナンス中心現在の標準。新規開発はこちら
接続の書き方開く・閉じるを自分で書くwith文で安全に開閉できる
結果を辞書で受け取る別途設定が必要row_factory=dict_row で簡単

ネット上にはpsycopg2の記事や書籍が今もたくさん残っているので、「どっちを入れればいいの?」と迷いやすいところです。新しく始める分は、psycopg3で統一しておけば大丈夫です。

SQLそのものにまだ慣れていない場合は、基礎がひと通りまとまった書籍を手元に1冊置いておくと助けになります。

→ SQL 第2版 ゼロからはじめるデータベース操作(Amazon)

PostgreSQLの新しい橋を渡るゾウとヘビ

準備:データベースとユーザーを作る

接続の前に、PostgreSQL側に「入れ物」を用意します。psqlかpgAdminで、次の2行を実行してください。

SQL
CREATE USER sample_user WITH PASSWORD 'sample_password';
CREATE DATABASE sample_db OWNER sample_user;
SQL

パスワードはあくまで例です。ご自分の環境では別の文字列に変えてください。このあとのコードでも、同じ値を使います。

データベースの持ち主(OWNER)を sample_user にするのがポイントです。PostgreSQL 15以降では、持ち主でないユーザーはテーブルを作れない決まりのため、この指定がないとステップ2で「スキーマ public へのアクセスが拒否されました」という権限エラーになります。

ステップ0:psycopg3をインストールする

仮想環境を有効にした状態で、次を実行します。

Bash
pip install "psycopg[binary]"
Bash

ここ、よくある間違いです。 pip install psycopg3 ではインストールできません。第3世代でも配布名は psycopg です。「psycopg2-binaryの後継が psycopg[binary]」と覚えてください。

ステップ1:最小構成で接続を確認する

まずは「つながること」だけを確認します。欲張らないのがコツです。

Python
import psycopg

with psycopg.connect(
    host="localhost",
    port=5432,
    dbname="sample_db",
    user="sample_user",
    password="sample_password",
) as conn:
    with conn.cursor() as cur:
        cur.execute("SELECT version();")
        row = cur.fetchone()
        print(row[0])
Python

実行して、PostgreSQLのバージョン文字列(PostgreSQL 16.x... のような表示)が出れば、接続は成功です。お疲れさまでした、ここが一番の山場です。

ポイントは2つあります。

  • with文を使うと、接続やカーソルを閉じ忘れません。これがpsycopg3らしい書き方です
  • psycopg2のときのように、cur.close() や conn.close() を自分で書く必要はありません

もしエラーが出たら、慌てずに後半の「接続できないときのチェックポイント」を見てください。エラーメッセージ別に対処をまとめています。

ステップ2:テーブルを作って、保存・取得してみる

接続できたら、今度は実際にデータを扱ってみましょう。「メモ」を保存する、小さなテーブルを作ります。

Python
import os

import psycopg
from psycopg.rows import dict_row

conninfo = (
    f"host={os.environ.get('PGHOST', 'localhost')} "
    f"port={os.environ.get('PGPORT', '5432')} "
    f"dbname={os.environ.get('PGDATABASE', 'sample_db')} "
    f"user={os.environ.get('PGUSER', 'sample_user')} "
    f"password={os.environ['PGPASSWORD']}"
)

with psycopg.connect(conninfo, row_factory=dict_row) as conn:
    with conn.cursor() as cur:
        # テーブルがなければ作る
        cur.execute(
            """
            CREATE TABLE IF NOT EXISTS memos (
                id SERIAL PRIMARY KEY,
                title TEXT NOT NULL,
                created_at TIMESTAMPTZ NOT NULL DEFAULT now()
            );
            """
        )
        # メモを1件追加する(値は %s で渡す)
        cur.execute(
            "INSERT INTO memos (title) VALUES (%s) RETURNING id;",
            ("はじめてのメモ",),
        )
        new_id = cur.fetchone()["id"]
        print(f"追加したメモのID: {new_id}")

        # 保存されたメモを全部取得する
        cur.execute("SELECT id, title, created_at FROM memos ORDER BY id;")
        for row in cur.fetchall():
            print(row)
Python

実行すると、追加したメモが {'id': 1, 'title': 'はじめてのメモ', 'created_at':...} のような「辞書」の形で表示されます。

ここで大事なのは、次の2点です。

値をSQL文に直接埋め込まない

VALUES (%s) と書いて、値は別に渡すのがpsycopgの作法です。文字列を組み立ててSQL文を作ると、SQLインジェクションというセキュリティ上の問題につながります。最初からこの書き方に慣れておくと、あとで困りません。

結果は辞書で受け取る

row_factory=dict_row を指定すると、結果を「列名:値」の辞書で受け取れます。「3列目はなんのデータだっけ?」と迷うことが減るので、初心者のうちほどおすすめです。

なお、このコードは接続情報を環境変数から読んでいます。実行前に、環境変数 PGPASSWORD にパスワードを設定しておいてください(PowerShellなら $env:PGPASSWORD = "sample_password")。理由は次の節で説明します。

接続情報は、環境変数で管理する

ステップ1のコードは分かりやすさを優先して、パスワードをコードに直接書きました。ただ、実際の運用ではおすすめしません。コードをGitHubなどに上げたとき、パスワードまで一緒に公開されてしまうからです。

考え方はシンプルです。

  • パスワードはコードに書かず、環境変数(または .env ファイル+ python-dotenv)に置く
  • コード側は os.environ で読み取るだけにする
  • .env ファイルは .gitignore に入れて、リポジトリには含めない

ステップ2のコードが、まさにその形です。最初はステップ1で接続を確認して、動いたらステップ2の形に寄せていく。この順番が無理がありません。

接続できないときのチェックポイント

うまく接続できない場合、Pythonコードよりも 環境側 に原因があることがほとんどです。エラーメッセージで当たりを付けましょう。

表示されるエラー(抜粋)原因の見当確認すること
connection refusedPostgreSQLが起動していない/ポートが違うサービスが起動しているか、ポートが5432か
password authentication failedユーザー名かパスワードが違う作成時の値と、コード側の値が一致しているか
database "sample_db" does not existデータベースを作っていないCREATE DATABASE を実行したか
ModuleNotFoundError: No module named 'psycopg'インストール先の環境が違う仮想環境を有効にしてからインストールしたか
pip install psycopg3 で失敗する配布名の勘違い正しくは pip install "psycopg[binary]"

切り分けのコツは、まずpsqlやpgAdminで直接ログインできるかを確認することです。そちらでつながらなければ原因はPostgreSQL側、つながるのにPythonからだけ失敗するなら、接続情報か仮想環境の問題だと分かります。

エラーのときに「何も表示されずに終わる」のを防ぐなら、こんな書き方もできます。

Python
import psycopg

try:
    with psycopg.connect(
        dbname="sample_db", user="sample_user", password="sample_password"
    ) as conn:
        print("接続できました")
except psycopg.OperationalError as e:
    print("接続できませんでした。PostgreSQLの起動と接続情報を確認してください")
    print(f"詳細: {e}")
Python

なぜSQLiteではなく、PostgreSQLなのか

Pythonで使えるデータベースには、SQLiteという選択肢もあります。

SQLiteは手軽で、小さなスクリプトや検証用途にはとても便利です。このブログでも、勤怠管理アプリはSQLiteで作りました。

→ Pythonで勤怠管理システムを自作する方法|Flask+SQLiteで最速MVP

ただ、次のような場面ではPostgreSQLの方が扱いやすくなります。

  • 複数の環境から同じDBに接続したい
  • Webアプリとして使いたい
  • データを継続的に蓄積したい

最初はSQLiteで始めて、「育ってきたな」と感じたタイミングでPostgreSQLに移行する。この流れも自然です。

この構成でできること・できないこと

ここまでの構成で、できることは次の通りです。

  • PythonスクリプトからDBを操作する
  • データの保存・取得を行う
  • FlaskなどのWebアプリに発展させる

一方で、次のことはこの段階では考えなくて大丈夫です。

  • 高負荷な本番運用
  • 複雑なDB設計や最適化
  • パフォーマンスチューニング

まずは「PythonからDBに触れる感覚」をつかむことを優先してください。

psycopg2から移行する人へ

すでにpsycopg2で書いたコードがある方は、次だけ押さえれば移行できます。

  • import psycopg2 → import psycopg に変わる
  • インストールは psycopg2-binary → psycopg[binary]
  • with psycopg.connect(...) as conn: と書けば、コミットとクローズは自動になる(psycopg2の with はクローズしなかった点が違います)
  • SQLのプレースホルダ %s の書き方は、そのまま使えます

既存コードを無理に全部書き換える必要はありません。新しく書く分からpsycopg3にする、で十分です。

よくある質問

Q. 手元の本や記事がpsycopg2前提でも、読み替えて進められますか?

はい、基本の流れ(接続→カーソル→SQL実行→取得)は同じです。importの名前とインストール名、with文の扱いだけ読み替えれば、ほとんどのサンプルはpsycopg3で動きます。

Q. pip install psycopg3 が失敗するのはなぜですか?

そういう名前の配布パッケージが存在しないからです。第3世代の正式な配布名は psycopg で、インストールは pip install "psycopg[binary]" と指定します。

Q. MacやLinuxでも同じコードで動きますか?

はい、この記事のPythonコードはOSに依存しません。違うのは、環境変数の設定方法やPostgreSQLの起動方法くらいです。

このあと多くの人がつまずくポイント

PythonからPostgreSQLに接続できたあと、多くの人が次に悩みます。

  • PCを閉じるとデータベースが止まる
  • 別の環境から接続できない
  • Webアプリから使いたくなった

これらは、Pythonコードの問題ではありません。「PostgreSQLをどこで動かしているか」という、置き場所の問題 です。

次の一歩:PostgreSQLを安定して動かすには

サーバーのそばで働くゾウ

学習や小さな開発を続けるなら、PostgreSQLが常に起動している環境を1つ用意しておくと楽になります。

Pythonからの接続が安定するので、私はこの用途専用にVPSを1台用意しました。ローカル環境で詰まる時間が減り、Pythonのコードそのものに集中しやすくなりました。

もちろん、「まずは自分のPCだけで試したい」という段階でも、まったく問題ありません。この記事でローカル接続まで確認できれば十分です。その先に進みたくなったときに、環境を切り替えればOKです。

→ Python用途に使いやすいVPSはこちら

まとめ

  • 今から始めるなら、ライブラリは psycopg3(psycopg[binary])
  • 接続できたら、テーブル作成→保存→取得まで一気に試すと感覚がつかめる
  • パスワードはコードに直接書かず、環境変数で管理する
  • つながらないときは、エラーメッセージから環境側を先に疑う

PythonからPostgreSQLに接続できるようになると、扱えるデータの幅が一気に広がります。

最初はローカル環境でも構いません。ただ、作業が増えてきたら「データベースの置き場所」を見直すだけで、Pythonの扱いやすさは変わります。ここまでできていれば、データベースを扱うための入口はクリアです。あとは、どこで動かし続けるかを選ぶだけです。

目次