Django+Reactで学ぶプログラミング基礎(18): Django高度なチュートリアル(再利用可能アプリの書き方)

##### [前回] [Django+Reactで学ぶプログラミング基礎(17): Djangoチュートリアル(投票アプリその7-3)](https://qiita.com/mingchun_zhao/items/a74e74bc37575464f6f5)

## はじめに

前回まで、公式チュートリアルを通して、Django基本を理解しました。
今回は、[Django高度なチュートリアル](https://docs.djangoproject.com/ja/4.0/intro/reusable-apps/): `再利用可能アプリの書き方`です。

## 今回の内容

- 再利用性の課題
- プロジェクトと再利用可能アプリ
- アプリをパッケージング
- 自分のパッケージを使ってみる
- アプリを公開する
- 仮想環境でPythonパッケージをインストール

## 再利用性の課題

- Webアプリの設計/開発/テスト/メンテナンスには多大な労力が必要
    - 多くのPythonプロジェクト、Djangoプロジェクトは共通の問題を抱えている
    - この繰り返し作業を減らせないか

- 再利用可能性はPythonの特徴
    - `The Python Package Index`(PyPI)には、Pythonプログラムに使用できる幅広いパッケージが揃っている
        - Djangoパッケージも再利用可能なアプリ
    - 既存のPythonパッケージやDjangoアプリを選んで、Webプロジェクトに組み込むことが可能
        - 開発者はプロジェクトに特有の部分にだけ取り組めば良い

- Pythonパッケージとは
    - 関連するPythonコードをまとめて再利用しやすいようにしたもの
        - Pythonコードのファイル(モジュール)を1つ以上含む
    - パッケージのインポート
        - `import foo.bar`
        - または、`from foo import bar`
    - パッケージのディレクトリ(例えば`polls`)
        - `__init__.py`という特殊なファイルを含む必要あり(空ファイルでよい)

- Djangoアプリとは
    - 単なるPythonパッケージ
    - Djangoプロジェクトで使うことのみ意図
    - アプリはDjangoの一般的な慣例に則っている
        - サブモジュール`models`、`tests`、`urls`、`views`が存在

- パッケージングとは
    - アプリを新規プロジェクトでインストール/利用できるように、パッケージを作るプロセス

- Pythonのパッケージングとは
    - 特定のフォーマットでアプリを作っておくこと
        - このフォーマットにより簡単にインストールし使用可能
        - Django自体もこのようにパッケージ化されている

## プロジェクトと再利用可能アプリ

- プロジェクトの構造
```
pollsite/
    manage.py
    mysite/
        __init__.py
        settings.py
        urls.py
        asgi.py
        wsgi.py
    polls/
        __init__.py
        admin.py
        apps.py
        migrations/
            __init__.py
            0001_initial.py
        models.py
        static/
            polls/
                images/
                    background.gif
                style.css
        templates/
            polls/
                detail.html
                index.html
                results.html
        tests.py
        urls.py
        views.py
    templates/
        admin/
            base_site.html
```

- 投票アプリに関する全ては`polls`に存在し、アプリが自己完結している
    - 新規プロジェクトに導入しやすくなっている

- `polls`ディレクトリは新規Djangoプロジェクトにコピーでき、すぐに再利用できる状態
    - しかし、公開するには、アプリをパッケージにして別の場所でインストールしやすいようにする必要あり

### パッケージの名前を決める

- `PyPI`のようなリソースをチェックし、すでに存在するパッケージ名との衝突を避ける
- Djangoアプリのパッケージを作って配布する際は、モジュール名の先頭に`django-`を付ける
- アプリラベルは`INSTALLED_APPS`の中で必ずユニーク
    - アプリラベルとは
        - アプリパッケージへのパス(ドット区切り)の最後の部分
    - `Django contrib packages`と同じラベルを避けるべき
        - `auth`、`admin`、`messages`など

## アプリをパッケージング

- 1\. はじめに、`polls`の親ディレクトリを、 Djangoプロジェクトの外に作成
    - VS Codeで、`ファイル`メニューから`フォルダーをワークスペースに追加`
        - `C:\kanban`ディレクトリを追加
    - `C:\kanban\django-polls`ディレクトリを作成
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/cc8e5019-0bee-5c8d-50f4-b3c1a0369256.png)
- 2\. `polls`ディレクトリを`django-polls`ディレクトリに移動
- 3\. `django-polls/README.rst`ファイルを作成
```
=====
Polls
=====

Polls is a Django app to conduct web-based polls. For each question,
visitors can choose between a fixed number of answers.

Detailed documentation is in the "docs" directory.

Quick start
-----------

1. Add "polls" to your INSTALLED_APPS setting like this::

    INSTALLED_APPS = [
        ...
        'polls',
    ]

2. Include the polls URLconf in your project urls.py like this::

    path('polls/', include('polls.urls')),

3. Run ``python manage.py migrate`` to create the polls models.

4. Start the development server and visit http://127.0.0.1:8000/admin/
   to create a poll (you'll need the Admin app enabled).

5. Visit http://127.0.0.1:8000/polls/ to participate in the poll.
```
- 4\. `django-polls/LICENSE`ファイルを作成
    - Djangoと多くのDjango互換アプリはBSDライセンスの元に配布される
    - どのライセンスを選択するかは自由
        - ライセンスの選択は、誰がコードを使えるかに影響する
- 5\. アプリビルドとインストール方法の説明ファイルを作成
    - `setuptools`の例
```django-polls/pyproject.toml
[build-system]
requires = ['setuptools>=40.8.0', 'wheel']
build-backend = 'setuptools.build_meta:__legacy__'
```
```django-polls/setup.cfg
[metadata]
name = django-polls
version = 0.1
description = A Django app to conduct web-based polls.
long_description = file: README.rst
url = https://www.example.com/
author = Your Name
author_email = yourname@example.com
license = BSD-3-Clause  # Example license
classifiers =
    Environment :: Web Environment
    Framework :: Django
    Framework :: Django :: X.Y  # Replace "X.Y" as appropriate
    Intended Audience :: Developers
    License :: OSI Approved :: BSD License
    Operating System :: OS Independent
    Programming Language :: Python
    Programming Language :: Python :: 3
    Programming Language :: Python :: 3 :: Only
    Programming Language :: Python :: 3.8
    Programming Language :: Python :: 3.9
    Topic :: Internet :: WWW/HTTP
    Topic :: Internet :: WWW/HTTP :: Dynamic Content

[options]
include_package_data = true
packages = find:
python_requires = >=3.8
install_requires =
    Django >= X.Y  # Replace "X.Y" as appropriate
```
```django-polls/setup.py
from setuptools import setup

setup()
```
- 6\. デフォルトでは、Pythonモジュールとパッケージのみがパッケージに含まれる
    - 追加のファイルを含めるには、`MANIFEST.in`ファイルを作成する必要あり
    - テンプレート、`README.rst`、`LICENSE`ファイルを含めるには
```django-polls/MANIFEST.in
include LICENSE
include README.rst
recursive-include polls/static *
recursive-include polls/templates *
```
- 7\. アプリのドキュメントを含める(任意だが、推奨される)
    - 空のディレクトリ`django-polls/docs`を将来のドキュメンテーションのため作っておく
    - `MANAFEST.in`に行を追加
        - 追加しないと、`docs`ディレクトリがパッケージに含まれない
    - 多くのDjangoアプリは、ドキュメントを`readthedocs.org`のようなサイトを通して提供
```django-polls/MANAFEST.in
recursive-include docs *
```
- 8\. パッケージをビルド
    - `django-polls`内で`python setup.py sdist`を実行
    - `dist`というディレクトリと、新しいパッケージ`django-polls-0.1.tar.gz`が作られる
```
(venv) C:\kanban\pollsite>cd ..\django-polls
(venv) C:\kanban\django-polls>python setup.py sdist
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/c506b694-13e1-cebd-2e99-4bc90623c94b.png)

## 自分のパッケージを使ってみる

- 1\. pipを利用し、`django-polls`パッケージをインストール
    - `django-polls`をユーザーライブラリとしてインストール
        - ユーザー単位のインストールはシステム全体のインストールより下記メリットあり
            - 管理者アクセス権を持っていないシステム上で使用可能
            - パッケージがシステムサービスや他ユーザーに影響を与えるのを防ぐ
        - ユーザー単位のインストールは、そのユーザーとして実行されるシステムツールの動作に影響を与える可能性あり
            - 対処: 仮想環境を使用するのが、より堅牢なソリューション(※後続)
    - VS Codeで新しいコマンドプロンプトを開く
        - コマンドプロンプトは`kanban C:\`を選択
            - `pollsite kanban`ではない
```
C:\kanban>python -m pip install --user django-polls/dist/django-polls-0.1.tar.gz
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/560709fe-3d8c-961d-90d8-7ce24f86c163.png)

- 2\. Djangoプロジェクトを動作させるため、サーバーを起動

- 3\. pipを使用し、パッケージをアンインストール
```
python -m pip uninstall django-polls
```

## アプリを公開する

- `django-polls`パッケージを公開
    - パッケージをメールで送る
    - Webサイトにアップロード
    - 公開されているリポジトリに投稿
        - `The Python Package Index`(PyPI)

## 仮想環境でPythonパッケージをインストール

- 投票アプリをユーザーライブラリにインストールした場合の欠点
    - ユーザーライブラリの変更は、システム上の他のPythonソフトウェアに影響を与えるおそれあり
    - このパッケージの複数バージョン(もしくは同じ名前の別のもの)を実行できない

- 通常、上記状況は複数Djangoプロジェクトを管理している場合のみ発生
    - 解決策: venvツールを使用し、複数の分離されたPython環境を管理
        - それぞれが独自のライブラリとパッケージの名前空間のコピーを持つ

## おわりに

再利用可能アプリに書き直し、パッケージを作成/公開しました。
次回も続きます。お楽しみに。

##### [次回] [Django+Reactで学ぶプログラミング基礎(19): Reactチュートリアル(準備とReact概要)](https://qiita.com/mingchun_zhao/items/cbcee727c4509b948d85)