もた日記

くだらないことを真面目にやる

Djangoメモ : データベースをSQLiteからPostgreSQLに変更する

Python 3.6.4 Django 2.0.2

A Complete Beginner's Guide to Djangoのチュートリアルを参考にデータベースをSQLiteからPostgreSQLに変更してみる。


PostgreSQLの設定

PostgreSQLはインストールしてあるものとして話を進める。

$ psql --version
psql (PostgreSQL) 10.1

今回はu_boardsというユーザーを作成し、django_boardsというデータベースを作成してみる。
最初にpostgresユーザーに切り替える。

$ sudo su - postgres

ユーザーとデータベースを作成し、パスワードを変更する(newpasswordのところは適切なパスワードを設定すること)。

$ createuser u_boards
$ createdb django_boards --owner u_boards
$ psql -c "ALTER USER u_boards WITH PASSWORD 'newpassword'"

postgresユーザーから抜ける。

$ exit

正しく接続できるか確認してみる。
テーブルはまだないので何も表示されない。

$ psql -U u_boards -d django_boards
Password for user u_boards:
psql (10.1)
Type "help" for help.

django_boards=> \d
Did not find any relations.


Djangoの設定

DjangoでPostgreSQLに接続するためにはpsycopg2が必要なのでインストールする。

$ pip install psycopg2

今回はPipenvで環境を構築しているので下記コマンドを実行。

$ pipenv install psycopg2

次にsettings.pyDATABASE_URLを変更する。

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'django_boards',
        'USER': 'u_boards',
        'PASSWORD' : 'newpassword',
        'HOST' : 'localhost',
        'PORT' : 5432,
    }
}

これで設定は完了だが複数の設定項目があり面倒。
django-environを使うと.envに下記行を記述し、

DATABASE_URL=postgres://u_boards:newpassword@localhost:5432/django_boards

settings.pyでは以下のように読み込むことができる。

DATABASES = {
    'default': env.db(),
}

パスワードも設定ファイルで管理できるので興味があれば下記記事を参照。

wonderwall.hatenablog.com


設定は完了したので接続できるか確認してみる。
問題がなければ以下のようにmigrationが適用されていないステータスが表示される。

$ python manage.py showmigrations
accounts
 (no migrations)
admin
 [ ] 0001_initial
 [ ] 0002_logentry_remove_auto_add
auth
 [ ] 0001_initial
 [ ] 0002_alter_permission_name_max_length
 [ ] 0003_alter_user_email_max_length
 [ ] 0004_alter_user_username_opts
 [ ] 0005_alter_user_last_login_null
 [ ] 0006_require_contenttypes_0002
 [ ] 0007_alter_validators_add_error_messages
 [ ] 0008_alter_user_username_max_length
 [ ] 0009_alter_user_last_name_max_length
boards
 [ ] 0001_initial
 [ ] 0002_topic_views
contenttypes
 [ ] 0001_initial
 [ ] 0002_remove_content_type_name
sessions
 [ ] 0001_initial

接続できているようなのでmigrateコマンドを実行する。

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, boards, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying boards.0001_initial... OK
  Applying boards.0002_topic_views... OK
  Applying sessions.0001_initial... OK

これで各テーブルが作成される。

django_boards=> \d
                        List of relations
 Schema |               Name                |   Type   |  Owner
--------+-----------------------------------+----------+----------
 public | auth_group                        | table    | u_boards
 public | auth_group_id_seq                 | sequence | u_boards
 public | auth_group_permissions            | table    | u_boards
 public | auth_group_permissions_id_seq     | sequence | u_boards
 public | auth_permission                   | table    | u_boards
 public | auth_permission_id_seq            | sequence | u_boards
 public | auth_user                         | table    | u_boards
 public | auth_user_groups                  | table    | u_boards
 public | auth_user_groups_id_seq           | sequence | u_boards
 public | auth_user_id_seq                  | sequence | u_boards
 public | auth_user_user_permissions        | table    | u_boards
 public | auth_user_user_permissions_id_seq | sequence | u_boards
 public | boards_board                      | table    | u_boards
 public | boards_board_id_seq               | sequence | u_boards
 public | boards_post                       | table    | u_boards
 public | boards_post_id_seq                | sequence | u_boards
 public | boards_topic                      | table    | u_boards
 public | boards_topic_id_seq               | sequence | u_boards
 public | django_admin_log                  | table    | u_boards
 public | django_admin_log_id_seq           | sequence | u_boards
 public | django_content_type               | table    | u_boards
 public | django_content_type_id_seq        | sequence | u_boards
 public | django_migrations                 | table    | u_boards
 public | django_migrations_id_seq          | sequence | u_boards
 public | django_session                    | table    | u_boards
(25 rows)

最後にアプリにアクセスして表示を確認(データは追加する必要がある)。

f:id:wonder-wall:20180404233827p:plain


(参考)django.db.utils.OperationalError: FATAL: Ident authentication failed for user

以下のようなメッセージが出て接続できない場合は、

$ python manage.py showmigrations

django.db.utils.OperationalError: FATAL:  Ident authentication failed for user "u_boards"

/var/lib/pgsql/10/data/pg_hba.confMETHODidentからmd5に変更する。

# IPv4 local connections:
host    all             all             127.0.0.1/32            md5
# IPv6 local connections:
host    all             all             ::1/128                 md5

再起動を忘れないこと。

sudo systemctl restart postgresql-10


(参考)AssertionError: database connection isn't set to UTC

f:id:wonder-wall:20180404233809p:plain

というエラーが出たので下記リンクを方法を試して解決した。

python - Django 1.9.2 AssertionError: database connection isn't set to UTC - Stack Overflow

pg_timezone_namesの値を確認して、

postgres=# select * from pg_timezone_names where name like 'UTC';
 name | abbrev | utc_offset | is_dst
------+--------+------------+--------
 UTC  | JST    | 09:00:00   | f
(1 row)

アップデート。

sudo yum update tzdata

アップデート後のpg_timezone_namesの値を確認。

postgres=# select * from pg_timezone_names where name like 'UTC';
 name | abbrev | utc_offset | is_dst
------+--------+------------+--------
 UTC  | UTC    | 00:00:00   | f
(1 row)

再起動すればアプリが表示されるようになる。


(参考)UserWarning: The psycopg2 wheel package will be renamed from release 2.8

psycopg2を使うと以下のような警告メッセージが表示される。

$ python manage.py showmigrations
/home/vagrant/.local/share/virtualenvs/myproject-j-SR1M6H/lib/python3.6/site-packages/psycopg2/__init__.py:144: UserWarning: The psycopg2 wheel package will be renamed from release 2.8; in order to keep installing from binary please use "pip install psycopg2-binary" instead. For details see: <http://initd.org/psycopg/docs/install.html#binary-install-from-pypi>.
  """)

メッセージにもあるように代わりに下記パッケージをインストールすると警告メッセージは表示されなくなる。

$ pip install psycopg2-binary


まとめ

  • SQLiteからPostgreSQLに変更した
  • psycopg2またはpsycopg2-binaryをインストールする
  • settings.pyにPostgreSQLの接続情報を記述する
  • django-environを使うとPostgreSQLの接続情報が設定ファイルで管理できる