Djangoで、GitHubに上げたDjangoアプリの再利用を試してみた

Djangoまわりのドキュメントを眺めていると、再利用可能なDjangoアプリという言い方を目にします。

では、どのようにすればDjangoアプリを再利用できるのか調べてみたところ、公式ドキュメントに記載がありました。
Advanced tutorial: How to write reusable apps | Django documentation | Django

そこで、GitHubに上げたDjangoアプリの再利用を試してみました。

 

環境

 

再利用可能なDjangoアプリの作成

以下の構成のDjangoアプリを作成します。

  • Class-basedなview
  • ModelFormを使ったフォーム
  • fixtureで初期データを投入

 
コマンドプロンプトにて、Djangoアプリを作成します。  

# virtualenv環境を作って、Djangoをインストール
d:\Sandbox>mkdir Django_form_sample
d:\Sandbox>cd Django_form_sample
d:\Sandbox\Django_form_sample>virtualenv -p c:\python34\python.exe env
d:\Sandbox\Django_form_sample>env\Scripts\activate
(env) d:\Sandbox\Django_form_sample>pip install django

# DjangoプロジェクトとDjangoアプリの作成
# `django-admin.py startproject myproject`(.pyあり)だと、`ImportError: No module named django.core`エラーになる
# 現在のフォルダにプロジェクトを作るため、末尾の`.`を忘れずに付ける
(env) d:\Sandbox\Django_form_sample>django-admin startproject myproject .
(env) d:\Sandbox\Django_form_sample>python manage.py startapp thinkami_reusable_app

 
ひな形ができたため、以下の必要なファイルを作成・更新します。各ファイルの詳細はGitHubのリポジトリにあります。

  • myproject/settings.py
  • myproject/urls.py
  • thinkami_reusable_app/urls.py
  • thinkami_reusable_app/models.py
  • thinkami_reusable_app/widgets.py
  • thinkami_reusable_app/forms.py
  • thinkami_reusable_app/views.py
  • thinkami_reusable_app/templates/form.html
  • thinkami_reusable_app/fixtures/initial_data.json

 
実際に動作するかを確認するため、マイグレーションと初期データのロードを行います。

(env) d:\Sandbox\Django_form_sample>python manage.py makemigrations
(env) d:\Sandbox\Django_form_sample>python manage.py migrate
(env) d:\Sandbox\Django_form_sample>python manage.py loaddata initial_data

 
http://localhost:8000/site/register/にアクセスし、動作を確認します。

フォーム

f:id:thinkAmi:20160111000852p:plain

 

Djangoから出力されたHTMLソース
<body>
<div id="main">
  <form method="post" action="" name="detail">
    <fieldset>
      <input type='hidden' name='csrfmiddlewaretoken' value='ikcYFvPfvvYuXlhdIrDN1t80ejAleTOH' />
      <p>
        <label for="id_registration_date">RegistrationDate:</label>
        <input id="id_registration_date" name="registration_date" type="date" value="2016-01-10" />
        <input id="initial-id_registration_date" name="initial-registration_date" type="hidden" value="2016-01-10 13:13:17+00:00" />
      </p>
      <p>
        <label for="id_pushed_0">Pushed:</label>
        <ul id="id_pushed">
          <li>
            <label for="id_pushed_0">
              <input id="id_pushed_0" name="pushed" type="radio" value="1" />radio1
            </label>
          </li>
          <li>
            <label for="id_pushed_1">
              <input id="id_pushed_1" name="pushed" type="radio" value="2" />radio2
            </label>
          </li>
          <li>
            <label for="id_pushed_2">
              <input id="id_pushed_2" name="pushed" type="radio" value="3" />radio3
            </label>
          </li>
        </ul>
      </p>
      <p>
        <label for="id_checked">YesNo:</label>
        <input id="id_checked" name="checked" type="checkbox" />
      </p>
      <p>
        <label for="id_checked_multiple_0">CheckdMultiple:</label>
        <ul id="id_checked_multiple">
          <li>
            <label for="id_checked_multiple_0">
              <input id="id_checked_multiple_0" name="checked_multiple" type="checkbox" value="1" />checkbox1
            </label>
          </li>
          <li>
            <label for="id_checked_multiple_1">
              <input id="id_checked_multiple_1" name="checked_multiple" type="checkbox" value="2" />checkbox2
            </label>
          </li>
          <li>
            <label for="id_checked_multiple_2">
              <input id="id_checked_multiple_2" name="checked_multiple" type="checkbox" value="3" />checkbox3
            </label>
          </li>
        </ul>
      </p>
      <p>
        <label for="id_selected">Selected:</label>
        <select id="id_selected" name="selected">
          <option value="" selected="selected">---------</option>
          <option value="1">select1</option>
          <option value="2">select2</option>
          <option value="3">select3</option>
        </select>
      </p>
      <p>
        <label for="id_selected_multiple">SelectedMultiple:</label>
        <select multiple="multiple" id="id_selected_multiple" name="selected_multiple">
          <option value="1">select_multi1</option>
          <option value="2">select_multi2</option>
          <option value="3">select_multi3</option>
        </select>
      </p>
      <p>
        <label for="id_input_text">InputText:</label>
        <input id="id_input_text" maxlength="255" name="input_text" type="text" />
      </p>
      <p>
        <label for="id_text_area">TextArea:</label>
        <textarea cols="40" id="id_text_area" name="text_area" rows="10"></textarea>
      </p>
      <input type="submit" id="save" value="Save">
    </fieldset>
  </form>
</div>
</body>

 

再利用アプリのためのGitHubリポジトリ作成

上記で作成したDjangoアプリを再利用するため、GitHubリポジトリを新規作成します。

 

GitHubとローカルにGitリポジトリを用意

GitHubリポジトリを作り、ローカルのフォルダD:\Sandbox\Django_reusable_form_samplegit cloneします。

 

再利用するDjangoアプリをコピー

D:\Sandbox\Django_form_sample\thinkami_reusable_appフォルダを、D:\Sandbox\Django_reusable_form_sampleへとコピーします。

 

再利用するときに必要なファイルの追加

D:\Sandbox\Django_reusable_form_sampleフォルダの中に、

  • README.rst
  • LICENSE
  • setup.py
  • MANIFEST.in

の4ファイルを以下の通りに作成します。なお、README.rstLICENSEの掲載は省略します。

 

setup.py

基本的にはDjango公式ドキュメントと同じです。

なお、include_package_data=Trueは、pip install時に含まれるフォルダやファイルをMANIFEST.inファイルにて指定する設定ですので、今回は省略しないようにします。
[Python] setuptools - SumiTomohikoの日記

...
setup(
    name='thinkami_reusable_app_sample',
    version='0.1',
    packages=['thinkami_reusable_app'],
    include_package_data=True,
    description='reusable django app sample',
    long_description=README,
    url='https://github.com/thinkAmi-sandbox/Django_reusable_form_sample',
...
)

 

MANIFEST.in

今回の再利用アプリでは、

  • viewのtemplates
  • modelのmigrations
  • modelの初期データ用のfixtures

を使っていますので、MANIFEST.inに設定を追加します。

include LICENSE
include README.rst
recursive-include thinkami_reusable_app/fixtures *
recursive-include thinkami_reusable_app/migrations *
recursive-include thinkami_reusable_app/templates *

 
以上で必要なファイルを用意できたため、GitHubへとpushしておきます。

 

Djangoアプリの再利用を確認

新規にDjangoアプリを作成、pipで上記の再利用可能なアプリをインストール・設定し、再利用できるかを確認します。

# Djangoプロジェクトの新規作成
d:\Sandbox>mkdir Django_reuse_app_project
d:\Sandbox>cd Django_reuse_app_project
d:\Sandbox\Django_reuse_app_project>virtualenv -p c:\python34\python.exe env
d:\Sandbox\Django_reuse_app_project>env\Scripts\activate
(env) d:\Sandbox\Django_reuse_app_project>pip install django
(env) d:\Sandbox\Django_reuse_app_project>django-admin startproject myproject .

# 再利用可能なDjangoアプリを、GitHubからpipでインストール
(env) d:\Sandbox\Django_reuse_app_project>pip install git+https://github.com/thinkAmi-sandbox/Django_reusable_form_sample.git
...
Successfully installed thinkami-reusable-app-sample-0.1

 
Djangoプロジェクトの設定を変更し、再利用可能なDjangoアプリが動作できるようにします。

Django_reuse_app_project\myproject\settings.py
...
INSTALLED_APPS = [
    ...
    'thinkami_reusable_app',
]
...
Django_reuse_app_project\myproject\urls.py
from django.conf.urls import url, include
...
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^reuse/', include('thinkami_reusable_app.urls', namespace='myform')),
]
...

 
マイグレーションとデータのロード・開発サーバの起動を行います。

# マイグレーション
(env) d:\Sandbox\Django_reuse_app_project>python manage.py migrate
...
  Applying thinkami_reusable_app.0001_initial... OK

# データのロード
(env) d:\Sandbox\Django_reuse_app_project>python manage.py loaddata initial_data

# 開発サーバの起動
(env) d:\Sandbox\Django_reuse_app_project>python manage.py runserver

 
http://localhost:8000/reuse/register/へアクセスすると、再利用可能なDjangoアプリの動作を確認できました。

f:id:thinkAmi:20160111001603p:plain

 

ソースコード

一番最初に作成した、再利用可能なDjangoアプリを含むDjangoプロジェクト

thinkAmi-sandbox/Django_form_sample

 

pip installできる再利用可能なDjangoアプリ

thinkAmi-sandbox/Django_reusable_form_sample

 

参考

再利用可能なアプリの考え方については、以下が参考になりました。
再利用可能なDjangoアプリ開発 超訳 - SPEAKER BREAKA