Python Django 入門トップページ


Django REST Framework による API 開発

  1. API とプロジェクトの概要
  2. Django REST Frameworkのインストール
  3. プロジェクトの作成
  4. 基本設定
  5. アプリケーションの作成と登録
  6. モデルの作成とマイグレーション
  7. テストデータの設定
  8. コメント一覧を出力する API
  9. コメント詳細情報を出力する API
  10. 新規投稿と更新・削除の API
  11. ページネーション
  12. 入力内容の検証(バリデーション)
  13. テストの自動化
  14. Shell でのユーザ登録
  15. Fixtures でのユーザ登録
  16. ユーザ認証を必須にする
  17. コメントにオーナ情報を追加
  18. 権限の設定:Case #1
  19. 権限の設定:Case #2
  20. Python から API への接続
  21. React アプリケーションからの API 接続と CORS エラーの回避

Django REST Framework による API 開発

Fixtures でのユーザ登録

前のページでは shell を使ってユーザ情報を登録しました.しかしながら,大きなシステムの開発途中では頻繁にデータベースをリセットすることになります.その都度 shell で一人ひとりのユーザ情報を登録することは手間がかかることから,ここでは一つのコマンド実行でまとめてユーザが登録できるように fixtures を作成します.

まず,SQLite を操作してすでに登録されているユーザ情報とパスワード情報を表示します.特にハッシュ化パスワードはコピーして次の手順で貼り付けることになります.

sqlite> select id, username, email from auth_user; ⏎
id|username|email
1|user_a|a@sample.com
2|user_b|b@sample.com
3|user_c|c@sample.com
sqlite>
sqlite> select password from auth_user; ⏎
password
pbkdf2_sha256$600000$Pyo5BUOSWvH6vHwbKOD05e$qbXt6gxpXNiVWNevy+pC7NTyif6FnJ/9G5R6BtAbt3k=
pbkdf2_sha256$600000$OuR4219xvoiaQlcmxcD41x$OVlnlgfNyWeaLn00KDXibU85Zbx2YDH5GbZ3UdIpOnA=
pbkdf2_sha256$600000$rMHLWfTGTpaUkz1cUGDUAk$dRG5oQiTL3ecjNMJfWDNNwh0FpYWv+mMvBgs7jZ9TmY=
sqlite>

次に,comments\fixtures フォルダに user-data.json ファイルを作成し,次の内容を登録します.特にパスワードには上の手順で得られたハッシュ化パスワードをコピーして利用してください.

comments\fixtures\user-data.json[
    {
        "model": "auth.user",
        "fields": {
            "username": "user_a",
            "first_name": "A.",
            "last_name":"Sample",
            "email": "a@sample.com",
            "password":"pbkdf2_sha256$600000$Pyo5BUOSWvH6vHwbKOD05e$qbXt6gxpXNiVWNevy+pC7NTyif6FnJ/9G5R6BtAbt3k=",
            "is_superuser": 0,
            "is_staff": 0,
            "is_active": 1,
            "date_joined": "2023-11-23T16:01:00.000"
        }
    },
    {
        "model": "auth.user",
        "fields": {
            "username": "user_b",
            "first_name": "B.",
            "last_name":"Sample",
            "email": "b@sample.com",
            "password":"pbkdf2_sha256$600000$OuR4219xvoiaQlcmxcD41x$OVlnlgfNyWeaLn00KDXibU85Zbx2YDH5GbZ3UdIpOnA=",
            "is_superuser": 0,
            "is_staff": 0,
            "is_active": 1,
            "date_joined": "2023-11-23T16:02:00.000"
        }
    },
    {
        "model": "auth.user",
        "fields": {
            "username": "user_c",
            "first_name": "C.",
            "last_name":"Sample",
            "email": "c@sample.com",
            "password":"pbkdf2_sha256$600000$rMHLWfTGTpaUkz1cUGDUAk$dRG5oQiTL3ecjNMJfWDNNwh0FpYWv+mMvBgs7jZ9TmY=",
            "is_superuser": 0,
            "is_staff": 0,
            "is_active": 1,
            "date_joined": "2023-11-23T16:03:00.000"
        }
    }
]

データベースを一旦リセットして,今作成した JSON ファイルを読み込みます.最初のリセットでは auth アプリケーションだけをロールバックしています.このとき admin アプリケーションのテーブルも同時にリセットされていますが,残りのアプリケーションのテーブルはリセットされていないことにも注意してください.つまり,コメントの一覧データは残っている状態です.

...\django_comment_api>python manage.py showmigrations ⏎
admin
 [X] 0001_initial
 [X] 0002_logentry_remove_auto_add
 [X] 0003_logentry_add_action_flag_choices
auth
 [X] 0001_initial
 [X] 0002_alter_permission_name_max_length
 [X] 0003_alter_user_email_max_length
 [X] 0004_alter_user_username_opts
 [X] 0005_alter_user_last_login_null
 [X] 0006_require_contenttypes_0002
 [X] 0007_alter_validators_add_error_messages
 [X] 0008_alter_user_username_max_length
 [X] 0009_alter_user_last_name_max_length
 [X] 0010_alter_group_name_max_length
 [X] 0011_update_proxy_permissions
 [X] 0012_alter_user_first_name_max_length
comments
 [X] 0001_initial
contenttypes
 [X] 0001_initial
 [X] 0002_remove_content_type_name
sessions
 [X] 0001_initial

...\django_comment_api>python manage.py migrate auth zero ⏎
Operations to perform:
  Unapply all migrations: auth
Running migrations:
  Rendering model states... DONE
  Unapplying auth.0012_alter_user_first_name_max_length... OK
  Unapplying auth.0011_update_proxy_permissions... OK
  Unapplying auth.0010_alter_group_name_max_length... OK
  Unapplying auth.0009_alter_user_last_name_max_length... OK
  Unapplying auth.0008_alter_user_username_max_length... OK
  Unapplying auth.0007_alter_validators_add_error_messages... OK
  Unapplying auth.0006_require_contenttypes_0002... OK
  Unapplying auth.0005_alter_user_last_login_null... OK
  Unapplying auth.0004_alter_user_username_opts... OK
  Unapplying auth.0003_alter_user_email_max_length... OK
  Unapplying auth.0002_alter_permission_name_max_length... OK
  Unapplying admin.0003_logentry_add_action_flag_choices... OK
  Unapplying admin.0002_logentry_remove_auto_add... OK
  Unapplying admin.0001_initial... OK
  Unapplying auth.0001_initial... OK

...\django_comment_api>python manage.py showmigrations ⏎
admin
 [ ] 0001_initial
 [ ] 0002_logentry_remove_auto_add
 [ ] 0003_logentry_add_action_flag_choices
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
 [ ] 0010_alter_group_name_max_length
 [ ] 0011_update_proxy_permissions
 [ ] 0012_alter_user_first_name_max_length
comments
 [X] 0001_initial
contenttypes
 [X] 0001_initial
 [X] 0002_remove_content_type_name
sessions
 [X] 0001_initial

...\django_comment_api>python manage.py migrate ⏎
Operations to perform:
  Apply all migrations: admin, auth, comments, contenttypes, sessions
Running migrations:
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... 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 auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK

...\django_comment_api>python manage.py loaddata comments\fixtures\user-data.json ⏎
Installed 3 object(s) from 1 fixture(s)

...\django_comment_api>

正しくユーザが登録されていることを SQLite で確認します.

sqlite> select * from auth_user; ⏎
id|password|last_login|is_superuser|username|last_name|email|is_staff|is_active|date_joined|first_name
1|pbkdf2_sha256$600000$Pyo5BUOSWvH6vHwbKOD05e$qbXt6gxpXNiVWNevy+pC7NTyif6FnJ/9G5R6BtAbt3k=||0|user_a|Sample|a@sample.com|0|1|2023-11-23 16:01:00|A.
2|pbkdf2_sha256$600000$OuR4219xvoiaQlcmxcD41x$OVlnlgfNyWeaLn00KDXibU85Zbx2YDH5GbZ3UdIpOnA=||0|user_b|Sample|b@sample.com|0|1|2023-11-23 16:02:00|B.
3|pbkdf2_sha256$600000$rMHLWfTGTpaUkz1cUGDUAk$dRG5oQiTL3ecjNMJfWDNNwh0FpYWv+mMvBgs7jZ9TmY=||0|user_c|Sample|c@sample.com|0|1|2023-11-23 16:03:00|C.
sqlite>

さらに curl コマンドでこれまでと同様に認証ができていること,さらに認証を経ずに閲覧できること,を確認します.

...\django_comment_api>curl http://127.0.0.1:8000/comments/ ⏎
{"count":11,"next":"http://127.0.0.1:8000/comments/?page=2","previous":null,"results":[{"id":13,"title":"0123456789","body":"012345678901234","updated_at":"2023-11-23T15:24:38.905335"},{"id":9,"title":"9個目のコメント","body":"コメントの本 文9","updated_at":"2023-11-23T11:20:00"}]}
...\django_comment_api>curl -u user_a:password http://127.0.0.1:8000/comments/ ⏎
{"count":11,"next":"http://127.0.0.1:8000/comments/?page=2","previous":null,"results":[{"id":13,"title":"0123456789","body":"012345678901234","updated_at":"2023-11-23T15:24:38.905335"},{"id":9,"title":"9個目のコメント","body":"コメントの本 文9","updated_at":"2023-11-23T11:20:00"}]}
...\django_comment_api>curl -u user_a:abc http://127.0.0.1:8000/comments/ ⏎
{"detail":"ユーザ名かパスワードが違います。"}
...\django_comment_api>

目次に戻る