Python3.4 + Djangoで作るWebアプリケーション(Part.2 アプリ開発編)

  • 110
    いいね
  • 3
    コメント
この記事は最終更新日から1年以上が経過しています。

概要

前回の環境構築に引き続き、今回はDjangoでWebアプリケーションを作っていきます。

環境構築を知りたい方は前回の記事を参考にしてください。
Python3.4 + Djangoで作るWebアプリケーション(Part.1 環境構築編)

DjangoでWebアプリケーションを作る

Djangoはサービス全体を示す「プロジェクト」という単位と、
サービスの1機能を示す「アプリケーション」という単位が存在します。
プロジェクトとアプリケーションの範囲は厳密に定義されているわけではありませんが、
モデル自体はアプリケーションごとに定義しますが、
実際のデータベースはプロジェクト全体で共有することになります。

ここではプロジェクト名を「pj1」、
アプリケーション名を「app1」という名前でを作っていきます。
Webアプケーションの例として、IPアドレスの利用状況を管理するアプリケーションを作っていきます。
なお、ここでは/vagrantディレクトリ配下にDjangoプロジェクトを作成していくことで、ホストマシン側のテキストエディタでアプリケーションファイルを編集しています。

Djangoプロジェクトを生成

まず初めにDjangoプロジェクトを作成していきます。

(venv_app1) [vagrant@localhost ~]$ cd /vagrant/django_apps/
(venv_app1) [vagrant@localhost django_apps]$

(venv_app1) [vagrant@localhost django_apps]$ django-admin startproject pj1

(venv_app1) [vagrant@localhost django_apps]$ ls -al
total 0
drwxr-xr-x 1 vagrant vagrant 136 Sep 18 14:36 .
drwxr-xr-x 1 vagrant vagrant 204 Sep 18 10:47 ..
drwxr-xr-x 1 vagrant vagrant 136 Sep 18 14:36 pj1
drwxr-xr-x 1 vagrant vagrant 272 Sep 18 06:12 venv_app1

プロジェクトを生成すると下記のようなディレクトリが作成されます。

pj1/
|-- manage.py
`-- pj1
    |-- __init__.py
    |-- settings.py
    |-- urls.py
    `-- wsgi.py

pj1/pj1ディレクトリ配下のファイル群が、全アプリケーションに共通する設定ファイルです。

またpj1ディレクトリ配下に自動で作成されるmanage.pyが、
Djangoを使ってWebアプリケーションを開発する上で様々な便利な機能を備えるプログラムです。

例えば、Djangoの開発用簡易Webサーバを立ち上げる機能などがあります。
これによりngixなどのWebサーバを用意せずとも、開発中のアプリケーションをWebブラウザで確認することが可能です。
以下のコマンドで、簡易Webサーバを起動します。

(venv_app1) [vagrant@localhost django_apps]$ python pj1/manage.py runserver 0.0.0.0:8000

起動後、ホストマシンのWebブラウザで下記URLを入力してみます。

http://192.168.33.15:8000/

成功すると、Webブラウザで以下の画面を確認することができます。

django_snapshot.png

Djanogプロジェクトの初期設定

アプリケーション全体で共通するDjangoプロジェクトの初期設定を進めていきます。

pj1/pj1/settings.pyを編集していきます。

(venv_app1) [vagrant@localhost]$ cd /vagrant/django_apps/
(venv_app1) [vagrant@localhost django_apps]$ vi pj1/pj1/settings.py
# 追加・削除した部分のみを記載しています。

# データベースはデフォルトでSQLiteが設定されているため、MySQLに変更する
 DATABASES = {
    'default': {

        # 以下を削除
        #'ENGINE': 'django.db.backends.sqlieete3',
        #'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),

        # 作成したデータベース情報を追記
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'app1_db',
        'USER': 'app1_user',
        'PASSWORD': 'app1_passwd',
        'HOST': 'localhost',
        'PORT': '3306',
    }
 }

(中略)

# 言語設定を英語から日本語に変更

# 以下を削除
# LANGUAGE_CODE = 'en-us'
# TIME_ZONE = 'UTC'

#以下を追記
LANGUAGE_CODE = 'ja'
TIME_ZONE = 'Asia/Tokyo'

pj1/pj1/settings.pyを変更すると言語設定が日本語に変更されています。
再び簡易Webサーバを起動して、ホストマシンWebブラウザでみてみましょう。
Djangoで作成されたデフォルトのWebページが日本語表示になったことが確認できます。

(venv_app1) [vagrant@localhost django_apps]$ python pj1/manage.py runserver 0.0.0.0:8000

django_ja_snapshot
django_ja_snapshot.png

以上でDjangoプロジェクトの初期設定は完了です。

データベースを初期化

データベースを初期化するため以下のコマンドを実行します。
実行するとSQL文が発行され、データベース「app1_db」に管理用テーブルが生成されます。
このときに対話形式で、管理者情報を入力する必要があります。
ここでは適当にID:admin, Pass:admin, e-mail:なしで作成しました。

(venv_app1) [vagrant@localhost django_apps]$ python pj1/manage.py migrate

Would you like to create one now? (yes/no): yes
Username (leave blank to use 'vagrant'): admin
Email address: (無記入でEnter)
Password: admin
Password (again): admin

もし管理者ユーザを増やしたいときは、下記コマンドを実行することで上記と同じ対話モードを実行することができます。

$ python pj1/manage.py createsuperuser

MariaDBにログインしてみると、データベースの中にDjango用テーブルが作成されていることが確認できます。

(venv_app1) [vagrant@localhost django_apps]$  mysql -u app1_user -papp1_passwd

MariaDB [app1_db]> USE app1_db;
Database changed

MariaDB [app1_db]> SHOW TABLES;
+----------------------------+
| Tables_in_app1_db          |
+----------------------------+
| auth_group                 |
| auth_group_permissions     |
| auth_permission            |
| auth_user                  |
| auth_user_groups           |
| auth_user_user_permissions |
| django_admin_log           |
| django_content_type        |
| django_migrations          |
| django_session             |
+----------------------------+
10 rows in set (0.00 sec)

上記を実行すると、Django 管理サイトが自動で生成されます。
簡易Webサーバを立ち上げて、ホストマシンのWebブラウザで確認してみましょう。

(venv_app1) [vagrant@localhost django_apps]$ python pj1/manage.py runserver 0.0.0.0:8000
http://192.168.33.15:8000/admin/

すると以下の管理サイトが表示されます。

django_admin_snapshot.png

Webブラウザで先ほど入力した管理者情報(ここではID:admin, PASS:admin)を入力すると管理サイトに入ることができます。

django_admin_login.png

データベースを直接触らずとも、この管理者画面で管理者ユーザやグループを追加することができます。

Djangoではユーザ管理に限らず、データベースが持つすべての情報をこの管理サイトで追加・修正・削除することができます。
このように専用アプリケーションを自分で作成せずとも、自動でデータベースの管理機能を作成してくれるところがDjangoの非常に便利な点です。

Djangoアプリケーションを生成

次に、Djangoアプリケーションを作っていきます。

(venv_app1) [vagrant@localhost django_apps]$ cd /vagrant/django_apps/pj1/
(venv_app1) [vagrant@localhost pj1]$ python manage.py startapp app1

アプリケーションを生成すると、pj1ディレクトリ配下に、さらにapp1ディレクトリが作成されます。
pj1/pj1ディレクトリ配下のファイル群が、全アプリケーションに共通する設定ファイルであることに対して、
pj1/app1ディレクトリ配下のファイル群がDjangoアプリケーション固有の設定ファイルです。

pj1/
|-- app1
|   |-- __init__.py
|   |-- admin.py
|   |-- migrations
|   |   `-- __init__.py
|   |-- models.py
|   |-- tests.py
|   `-- views.py
|-- manage.py
`-- pj1
    |-- __init__.py
    |-- __pycache__
    |   |-- __init__.cpython-34.pyc
    |   `-- settings.cpython-34.pyc
    |-- settings.py
    |-- urls.py
    `-- wsgi.py

モデルを定義する

ここからアプリケーションの中身を作っていきます。
まずモデルを定義し、データベースのテーブル構造を定義していきます。

Djangoでは、アプリケーションごとのディレクトリ配下のmodels.pyを修正し、
テーブルをClass、フィールドを変数として定義していきます。

モデル要件

ここでは、IPアドレスを管理するアプリケーションを想定して、以下のようなモデルを定義します。

  • IPアドレスの利用状況を管理するアプリケーション
    • IP addressテーブル
    • IP addressフィールド
      • 所有するIPv4アドレス群を示す
      • ネットワークセグメントは無視して、/32のアドレス単体を管理
      • 値は一意
    • Statusフィールド
      • IPアドレスの利用状況のステータスを保持
      • in_use / avalable / not_available の3つの状態を持つ
      • ブランクの状態は許可しない
    • Descriptionフィールド
      • IPアドレスの利用状況についてのメモ
      • 自由記述可
      • ブランクの状態を許可する

models.pyの編集

モデル要件を満たすように pj1/app1/models.pyを以下のように編集します。
status_listという状態候補を用意することで、管理サイトやWebアプリケーションから
プルダウンメニューでの選択を指定することができます。

(venv_app1) [vagrant@localhost django_apps]$ vi pj1/app1/models.py

from django.db import models

class Ipaddress(models.Model):

    status_list = (
        ('in_use', 'in use'),
        ('available', 'available'),
        ('not_available', 'not available')
    )
    ipaddress = models.GenericIPAddressField(verbose_name='IP address', unique=True)
    status = models.CharField(verbose_name='Status', choices=status_list, max_length=16)
    description = models.CharField(verbose_name='Discription', blank = True, max_length=255)

Djangoアプリケーションのモデル定義を有効化

次にDjangoプロジェクトに対して、「app1」のモデル定義を有効化します。

pj1/pj1/settings.pyの「INSTALLED_APPS」に追記します。

(venv_app1) [vagrant@localhost django_apps]$ vi pj1/pj1/settings.py
INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    #アプリケーション名を追記
    'app1'
 )

モデル定義をデータベースに反映

次に追加したモデルをデータベースに反映させます。

以下のコマンドでデータベースとの差分内容をSQL文にして発行します。
(この時点ではSQLの実行はされていません。)

(venv_app1) [vagrant@localhost django_apps]$ python pj1/manage.py makemigrations app1

Migrations for 'app1':
  0001_initial.py:
    - Create model IPaddress

発行されたSQL文は下記コマンドで確認できます。

(venv_app1) [vagrant@localhost django_apps]$ python pj1/manage.py sqlmigrate app1 0001

BEGIN;
CREATE TABLE `app1_ipaddress` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `ipaddress` char(39) NOT NULL UNIQUE, `status` varchar(16) NOT NULL, `description` varchar(255) NOT NULL);

COMMIT;

次に、以下のコマンドで発行されたSQL文を実行します。この時点でデータベースが更新されます。

(venv_app1) [vagrant@localhost django_apps]$ python pj1/manage.py migrate

Operations to perform:
  Synchronize unmigrated apps: staticfiles, messages
  Apply all migrations: admin, app1, auth, contenttypes, sessions
Synchronizing apps without migrations:
  Creating tables...
    Running deferred SQL...
  Installing custom SQL...
Running migrations:
  Rendering model states... DONE
  Applying app1.0001_initial... OK

MariaDBで確認すると新たにテーブル「app1_ipaddress 」が追加されたことが確認できます。

(venv_app1) [vagrant@localhost django_apps]$ mysql -u app1_user -papp1_passwd

MariaDB [(none)]> USE app1_db;
Database changed

MariaDB [app1_db]> SHOW TABLES;
+----------------------------+
| Tables_in_app1_db          |
+----------------------------+
| app1_ipaddress              |
| auth_group                 |
| auth_group_permissions     |
| auth_permission            |
| auth_user                  |
| auth_user_groups           |
| auth_user_user_permissions |
| django_admin_log           |
| django_content_type        |
| django_migrations          |
| django_session             |
+----------------------------+
11 rows in set (0.00 sec)

以降、models.pyを編集するたびに「python pj1/manage.py makemigrations app1」「python pj1/manage.py migrate」の2つのコマンドを実行することでデータベースを変更していきます。

管理サイトでアプリケーション用テーブルを登録

データベースは更新されましたが、現時点では管理サイト上にapp1用のテーブルは追加されていません。
管理サイトで管理するためにはapp1ディレクトリ配下のadmin.pyを編集していきます。

vi pj1/app1/admin.py
from django.contrib import admin

# 追記
from app1.models import Ipaddress

# 追記
admin.site.register(Ipaddress)

簡易Webサーバを立ち上げ、ホストマシンのWebブラウザで管理サイトを確認します。

(venv_app1) [vagrant@localhost django_apps]$ python pj1/manage.py runserver 0.0.0.0:8000
http://192.168.33.15:8000/admin/

このようにDjango 管理サイトにapp1のテーブル情報が表示されます。

django_admin_app1_regist_snapshot.png

値を入力して「追加」のボタンを押すことで、Ipaddressテーブルに値が追加できます。

次に管理サイトを使って、3つのIPアドレス情報を登録してみます。

IP address : 192.168.0.0
Status: not_available
Discription: Network address

IP address : 192.168.0.1
Status: available
Discription: (blank)

IP address : 192.168.0.2
Status: available
Discription: (blank)

ここで管理サイト上に、登録した情報を出力させるには、models.pyにstr関数を追加する必要があります。

(venv_app1) [vagrant@localhost django_apps]$ vi pj1/app1/models.py
from django.db import models

class Ipaddress(models.Model):
    status_list = (
        ('in_use', 'in use'),
        ('available', 'available'),
        ('not_available', 'not available')
    )
    ipaddress = models.GenericIPAddressField(verbose_name='IP address', unique=True)
    status = models.CharField(verbose_name='Status', choices=status_list, max_length=16)
    description = models.CharField(verbose_name='Discription', blank = True, max_length=255)

    # ここを追加
    def  __str__(self):
        return self.ipaddress

このようにすると、IPaddressテーブルの中身を表示させることができるようになります。

django_admin_app1_regist2_snapshot.png

さらに、IPaddressテーブルのフィールド情報も表示させる場合はadmin.pyを編集します。

(venv_app1) [vagrant@localhost django_apps]$ vi pj1/app1/admin.py
from django.contrib import admin
from app1.models import Ipaddress

# 以下を追加
class IpaddressAdmin(admin.ModelAdmin):
    list_display = ('ipaddress', 'status', 'description')

admin.site.register(Ipaddress, IpaddressAdmin)

このようにすることで管理サイトの表示をカスタマイズしていくことができます。

django_admin_app1_regist3_snapshot.png

念のため、実際のデータベースで正しくアドレス情報が追加されたか確認しておきます。

(venv_app1) [vagrant@localhost django_apps]$ mysql -u app1_user -papp1_passwd

MariaDB [(none)]> USE app1_db;

MariaDB [app1_db]> SELECT * FROM app1_ipaddress;
+----+-------------+--------------+-----------------+
| id | ipaddress   | status       | description     |
+----+-------------+--------------+-----------------+
|  1 | 192.168.0.0 | not_avilable | Network address |
|  2 | 192.168.0.1 | available    |                 |
|  3 | 192.168.0.2 | available    |                 |
+----+-------------+--------------+-----------------+
3 rows in set (0.00 sec)

このようにして、DjangoではSQLコマンドを叩かずに管理サイトからレコード情報を追加・削除していくことができます。

Tips データベースのレコード情報をテキストファイルに書き出す

データベースを扱っていると、その時点での情報を書き出す場面が出て来ます。
Djangoではデータベースのレコード情報をJSON/XML/YAMLのいずれかの形式で書き出す機能があります。
ここではJSON形式で書き出します。

(venv_app1) [vagrant@localhost django_apps]$ mkdir pj1/app1/dumpdata

(venv_app1) [vagrant@localhost django_apps]$ python pj1/manage.py dumpdata app1 --format=json --indent=2 -o pj1/app1/dumpdata/ap1_db_dump.json
(venv_app1) [vagrant@localhost django_apps]$ cat pj1/app1/dumpdata/ap1_db_dump.json
[
{
  "pk": 1,
  "fields": {
    "status": "not_avilable",
    "ipaddress": "192.168.0.0",
    "description": "Network address"
  },
  "model": "app1.ipaddress"
},
{
  "pk": 2,
  "fields": {
    "status": "available",
    "ipaddress": "192.168.0.1",
    "description": ""
  },
  "model": "app1.ipaddress"
},
{
  "pk": 3,
  "fields": {
    "status": "available",
    "ipaddress": "192.168.0.2",
    "description": ""
  },
  "model": "app1.ipaddress"
}
]

作成されたファイルをgitで管理しておけば、レコード情報を時系列で管理することができます。

なお、書き出したファイルを読み込みたい場合は、下記のコマンドを実施します。

(venv_app1) [vagrant@localhost django_apps]$ python pj1/manage.py loaddata pj1/app1/dumpdata/ap1_db_dump.json

Installed 3 object(s) from 1 fixture(s)

DjangoアプリケーションのViewを定義

モデル部分ができたので、次はDjangoアプリケーション表示を決定するViewを作っていきます。

URLを定義

まずはWebアプリケーションのURLを定義します。
pj1/pj1/ulrs.pyを編集することでDjangoアプリケーション単位のURLを定義します。
Djangoアプリケーションごとのページなどのさらに細かいURLを定義するときは、
アプリケーションディレクトリ配下のurls.pyを作成して追加してます。

まずpj1/pj1/ulrs.pyを修正します。
ここでは、 以下のURLが有効になるように設定しています。
http://192.168.33.15:8000/app1/

 (venv_app1) [vagrant@localhost django_apps]$ vi pj1/pj1/urls.py
from django.conf.urls import include, url
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),

    # 下記を追加
    url(r'^app1/', include('app1.urls', namespace = 'app1')),
]

次に、アプリケーションディレクトリ配下に新たにulrs.pyを作成します。
ここでは以下のURLが有効になるように設定しています。
- http://192.168.33.15:8000/app1/ipaddress/

 (venv_app1) [vagrant@localhost django_apps]$ vi pj1/app1/urls.py
from django.conf.urls import patterns, url
from app1 import views

urlpatterns = [
    url(r'^ipaddress/^$', views.index, name='ipaddress_list'),
]

Viewを定義( Hello Django編 )

アプリケーションディレトクリ配下のveiws.pyを編集することでview定義します。
まずは最も単純な「Hello Django」と表示するだけのViewを定義します。

(venv_app1) [vagrant@localhost django_apps]$ vi pj1/app1/models.py
from django.http import HttpResponse

def ipaddress(request):
    return HttpResponse("Hello Django")

簡易Webサーバを立ち上げて、ホストマシンのWebブラウザで確認してみます。

(venv_app1) [vagrant@localhost django_apps]$ python pj1/manage.py runserver 0.0.0.0:8000
http://192.168.33.15:8000/app1/ipaddress/

django_hello.png

単純な文字表示だけのWebアプリケーションであればこのように作成できますが、
もう少し情報の多いWebアプリケーションはテンプレートエンジンやBootstrapなどのCSSフレームワークを利用して開発していきます。

Bootstrapのインストール

以降のWebアプリケーションでは、CSSフレームワークであるBootstrapを使っていきます。
Bootstrapを利用すると、最低限のhtml記述だけで見栄えが整ったWebページを作成することができます。

まずBootstrapをダウンロードします。

(venv_app1) [vagrant@localhost django_apps]$ sudo wget https://github.com/twbs/bootstrap/releases/download/v3.3.5/bootstrap-3.3.5-dist.zip

(venv_app1) [vagrant@localhost django_apps]$ sudo yum install -y unzip

(venv_app1) [vagrant@localhost django_apps]$ sudo unzip bootstrap-3.3.5-dist.zip

正しく展開されると、下記のようなディレクリ構成になっています。

bootstrap-3.3.5-dist
|-- css
|   |-- bootstrap-theme.css
|   |-- bootstrap-theme.css.map
|   |-- bootstrap-theme.min.css
|   |-- bootstrap.css
|   |-- bootstrap.css.map
|   `-- bootstrap.min.css
|-- fonts
|   |-- glyphicons-halflings-regular.eot
|   |-- glyphicons-halflings-regular.svg
|   |-- glyphicons-halflings-regular.ttf
|   |-- glyphicons-halflings-regular.woff
|   `-- glyphicons-halflings-regular.woff2
`-- js
    |-- bootstrap.js
    |-- bootstrap.min.js
    `-- npm.js

次に、Bootstrapで利用するJavaScriptライブラリであるjQueryをダウンロードします。

(venv_app1) [vagrant@localhost django_apps]$ sudo wget http://code.jquery.com/jquery-2.1.4.min.js

jQueryのファイルを、さきほどダウンロードしたboostrapの「bootstrap-3.3.5-dist/js/」に移動します。

(venv_app1) [vagrant@localhost django_apps]$ mv jquery-2.1.4.min.js bootstrap-3.3.5-dist/js/
bootstrap-3.3.5-dist
|-- css
|   |-- bootstrap-theme.css
|   |-- bootstrap-theme.css.map
|   |-- bootstrap-theme.min.css
|   |-- bootstrap.css
|   |-- bootstrap.css.map
|   `-- bootstrap.min.css
|-- fonts
|   |-- glyphicons-halflings-regular.eot
|   |-- glyphicons-halflings-regular.svg
|   |-- glyphicons-halflings-regular.ttf
|   |-- glyphicons-halflings-regular.woff
|   `-- glyphicons-halflings-regular.woff2
`-- js
    |-- bootstrap.js
    |-- bootstrap.min.js
    |-- jquery-2.1.4.min.js
    `-- npm.js

次に「pj1/app1」のアプリケーションディレクトリ配下に「static」ディレクトリを新規作成し、
さきほどのbootstrap-3.3.5-distディレクトリ配下の全ファイルを を移動させます。

(venv_app1) [vagrant@localhost django_apps]$ mkdir pj1/app1/static
(venv_app1) [vagrant@localhost django_apps]$ mv bootstrap-3.3.5-dist/* pj1/app1/static/

最終的にこのようなディレクトリ構成になります。

pj1
|-- app1
|   |-- __init__.py
|   |-- __pycache__
|   |   |-- __init__.cpython-34.pyc
|   |   |-- admin.cpython-34.pyc
|   |   `-- models.cpython-34.pyc
|   |-- admin.py
|   |-- dumpdata
|   |   `-- ap1_db_dump.json
|   |-- migrations
|   |   |-- 0001_initial.py
|   |   |-- __init__.py
|   |   `-- __pycache__
|   |       |-- 0001_initial.cpython-34.pyc
|   |       `-- __init__.cpython-34.pyc
|   |-- models.py
|   |-- static
|   |   |-- css
|   |   |   |-- bootstrap-theme.css
|   |   |   |-- bootstrap-theme.css.map
|   |   |   |-- bootstrap-theme.min.css
|   |   |   |-- bootstrap.css
|   |   |   |-- bootstrap.css.map
|   |   |   `-- bootstrap.min.css
|   |   |-- fonts
|   |   |   |-- glyphicons-halflings-regular.eot
|   |   |   |-- glyphicons-halflings-regular.svg
|   |   |   |-- glyphicons-halflings-regular.ttf
|   |   |   |-- glyphicons-halflings-regular.woff
|   |   |   `-- glyphicons-halflings-regular.woff2
|   |   `-- js
|   |       |-- bootstrap.js
|   |       |-- bootstrap.min.js
|   |       |-- jquery-2.1.4.min.js
|   |       `-- npm.js
|   |-- tests.py
|   |-- urls.py
|   `-- views.py
|-- manage.py
`-- pj1
    |-- __init__.py
    |-- __pycache__
    |   |-- __init__.cpython-34.pyc
    |   |-- settings.cpython-34.pyc
    |   |-- urls.cpython-34.pyc
    |   `-- wsgi.cpython-34.pyc
    |-- settings.py
    |-- urls.py
    `-- wsgi.py

次に、Django からBootsrapを操作するために django-bootstrap-formというPythonパッケージをインストールします。

(venv_app1) [vagrant@localhost django_apps]$ pip install django-bootstrap-form

(venv_app1) [vagrant@localhost django_apps]$ pip list
Django (1.8.4)
django-bootstrap-form (3.2)
mysqlclient (1.3.6)
pip (7.1.2)
setuptools (12.0.5)
uWSGI (2.0.11.1)

次に、pj1/setting.pyのINSTALLED_APPSに、django-bootstrap-formを追記します。

(venv_app1) [vagrant@localhost django_apps]$ vi pj1/settings.py


INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    ##以下を追記
    'bootstrapform',

    'app1'
)

テンプレートを作成

HTMLファイルのテンプレートを作っていきます。DjangoではDjango template language (DTL)というテンプレートエンジンを使い、
HTMLテンプレートに変数を埋め込むことでWebアプリケーションを作成していきます。

DTLでは、{{ }} や {% %} で括った値を変数やプログラミング関数として扱うことができます。

今回のIPアドレス管理アプリケーションに合わせて、HTMLテンプレートを作成します。
テンプレートは、「app1/templates/」ディレクトリ配下に配置します。

ここでは、Bootstrap Getting Startedで紹介されている以下のページを参考に作っています。

(venv_app1) [vagrant@localhost django_apps]$ mkdir pj1/app1/templates
(venv_app1) [vagrant@localhost django_apps]$ vi pj1/app1/templates/ipaddress.html
{% load staticfiles %}

<!-- Adjust  bootstrap  navbar -->
body { padding-top: 40px; }

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>App1</title>

    <link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
    <link href="{% static 'css/bootstrap-theme.min.css' %}" rel="stylesheet">
    <script src="{% static 'js/jquery-2.1.4.min.js' %}"></script>
    <script src="{% static 'js/bootstrap.min.js' %}"></script>
  </head>

  <body>
    <nav class="navbar navbar-inverse navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">App1</a>
        </div>
        <div id="navbar" class="collapse navbar-collapse">
          <ul class="nav navbar-nav">
            <li class="active"><a href="#">IP address</a></li>
            <li><a href="#">Function 2</a></li>
            <li><a href="#">Function 3</a></li>
          </ul>
        </div><!--/.nav-collapse -->
      </div>
    </nav>

    <div class="container">
        <h1 class="page-header">IP address</h1>
        <table class="table table-striped table-bordered">

            <thead>
                <tr>
                    <td>IP address</td>
                    <td>Status</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                {% for ipaddress in ipaddresses %}
                <tr>
                    <td>{{ ipaddress.ipaddress }}</td>
                    <td>{{ ipaddress.status }}</td>
                    <td>{{ ipaddress.description }}</td>
                </tr>
                {% endfor %}
            </tbody>
        </table>

    </div><!-- /.container -->

  </body>
</html>

Viewを定義( IPアドレス表示編 )

作成したテンプレートに合わせて、データベースにあるIPアドレスの情報を表示させるアプリケーションを作ってみます。
pj1/app1/views.py を以下のように修正します。

(venv_app1) [vagrant@localhost django_apps]$ vi pj1/app1/models.py
from django.http import HttpResponse
from django.shortcuts import render_to_response
from django.template import RequestContext
from app1.models import Ipaddress

def ipaddress(request):
    # データベース上のIPアドレス情報を配列型で取得
    ipaddresses = Ipaddress.objects.all().order_by('id')

    return  render_to_response(
        'ipaddress.html', # テンプレート名を指定
        {'ipaddresses' : ipaddresses }, # 取得したIPアドレス情報をテンプレート内の変数に代入
        context_instance=RequestContext(request)
        )

簡易Webサーバを立ち上げて、ホストマシンのWebブラウザで確認してみます。

(venv_app1) [vagrant@localhost django_apps]$ python pj1/manage.py runserver 0.0.0.0:8000
http://192.168.33.15:8000/app1/ipaddress/

django_app_ipaddresslist.png

このようにテンプレートファイルとView定義を組み合わせることで、比較的少ない記述でDjangoアプリケーションを作成することができます。

Viewを定義( IPアドレス管理編 )

次は応用編として、アプリケーションにIPアドレス情報の変更機能を追加してみます。
詳細の解説はしませんが、変更したファイルを書いておきます。

まずapp1/urls.pyを下記のように編集します。
ここでは新たにhttp://192.168.33.15:8000/app1/ipaddress/change/1/ などのURLを定義し、
データベース上のIPアドレス情報のプライマリIDが「ipaddress_id」に紐づくように指定しています。

(venv_app1) [vagrant@localhost django_apps]$ vi pj1/app1/urls.py
from django.conf.urls import patterns, url
from app1 import views

urlpatterns = [
    url(r'^ipaddress/$', views.ipaddress, name='ipaddress'),
    url(r'^ipaddress/change/(?P<ipaddress_id>\d+)/$', views.ipaddress_change, name='ipaddress_change'),
]

次に、ipaddressテーブルのフィールド情報をそのまま値を変更できるようにするために、app1/forms.pyを作成します。
forms.pyを作成することで、HTMLテンプレートに{{ form }}と記述することで全フィールドを呼び出すことができます。

(venv_app1) [vagrant@localhost django_apps]$ vi pj1/app1/forms.py
from django.forms import ModelForm
from app1.models import Ipaddress

class IpaddressForm(ModelForm):
    class Meta:
        model = Ipaddress
        fields = ('id', 'ipaddress', 'status', 'description')

次に、app1/veiws.pyを以下のように追記します。

(venv_app1) [vagrant@localhost django_apps]$ vi pj1/app1/views.py
# -*- coding: utf-8 -*-
from django.http import HttpResponse
from django.shortcuts import render_to_response,  get_object_or_404, redirect
from django.template import RequestContext
from app1.models import Ipaddress
from app1.forms import IpaddressForm

def ipaddress(request):
    ipaddresses = Ipaddress.objects.all().order_by('id')

    return  render_to_response(
        'ipaddress.html',
        {'ipaddresses' : ipaddresses },
        context_instance=RequestContext(request)
        )

def ipaddress_change(request, ipaddress_id=None):

    if ipaddress_id:
        ipaddress =  get_object_or_404(Ipaddress, pk=ipaddress_id)
    else:
        ipaddress = Ipaddress()

    if request.method == 'POST':
        # 基本的にPOSTが推奨される
        form = IpaddressForm(request.POST, instance=ipaddress)
        if form.is_valid():
            form = form.save(commit=False)
            form.save()
            return redirect('app1:ipaddress')
    else:
        # GETの場合はこちらを実行
        form = IpaddressForm(instance=ipaddress)

    return  render_to_response(
        'ipaddress_change.html',
        dict(form=form, ipaddress_id=ipaddress_id),
        context_instance=RequestContext(request)
        )

テンプレートファイルapp1/template/ipaddress.htmlを以下のように追記します。

(venv_app1) [vagrant@localhost django_apps]$ vi pj1/app1/templates/ipaddress.html
{% load staticfiles %}

<!-- Adjust  bootstrap  navbar -->
body { padding-top: 40px; }

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>App1</title>

    <link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
    <link href="{% static 'css/bootstrap-theme.min.css' %}" rel="stylesheet">
    <script src="{% static 'js/jquery-2.1.4.min.js' %}"></script>
    <script src="{% static 'js/bootstrap.min.js' %}"></script>
  </head>

  <body>
    <nav class="navbar navbar-inverse navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">App1</a>
        </div>
        <div id="navbar" class="collapse navbar-collapse">
          <ul class="nav navbar-nav">
            <li class="active"><a href="#">IP address</a></li>
            <li><a href="#">Function 2</a></li>
            <li><a href="#">Function 3</a></li>
          </ul>
        </div><!--/.nav-collapse -->
      </div>
    </nav>

    <div class="container">
        <h1 class="page-header">IP address</h1>
        <table class="table table-striped table-bordered">

            <thead>
                <tr>
                    <td>ID</td>
                    <td>IP address</td>
                    <td>Status</td>
                    <td>Description</td>
                    <td>Function</td>
                </tr>
            </thead>
            <tbody>
                {% for ipaddress in ipaddresses %}
                <tr>
                    <td>{{ ipaddress.id }}</td>
                    <td>{{ ipaddress.ipaddress }}</td>
                    <td>{{ ipaddress.status }}</td>
                    <td>{{ ipaddress.description }}</td>
                    <td>
                        <a href="{% url 'app1:ipaddress_change' ipaddress_id=ipaddress.id  %}" class="btn btn-default btn-sm">Change Status</a>
                    </td>
                </tr>
                {% endfor %}
            </tbody>
        </table>
    </div><!-- /.container -->


  </body>
</html>

また、変更機能のために新たにテンプレートファイルapp1/template/ipaddress_change.htmlを作成します。
前半はapp1/template/ipaddress.htmlの内容をコピーしています。

(venv_app1) [vagrant@localhost django_apps]$ vi pj1/app1/templates/ipaddress_change.html
{% load staticfiles %}

<!-- Adjust  bootstrap  navbar -->
body { padding-top: 40px; }

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>App1</title>

    <link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
    <link href="{% static 'css/bootstrap-theme.min.css' %}" rel="stylesheet">
    <script src="{% static 'js/jquery-2.1.4.min.js' %}"></script>
    <script src="{% static 'js/bootstrap.min.js' %}"></script>
  </head>

  <body>
    <nav class="navbar navbar-inverse navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">App1</a>
        </div>
        <div id="navbar" class="collapse navbar-collapse">
          <ul class="nav navbar-nav">
            <li class="active"><a href="#">IP address</a></li>
            <li><a href="#">Function 2</a></li>
            <li><a href="#">Function 3</a></li>
          </ul>
        </div><!--/.nav-collapse -->
      </div>
    </nav>

    <div class="container">
      <h3 class="page-header">Change Status</h3>
      <form action="" method="post" class="form-horizontal" role="form">
          {% csrf_token %}
          {{ form }}
          <div class="form-group">
            <div class="container">
                <button type="submit" class="btn btn-primary">Change Status</button>
                <a href="{% url 'app1:ipaddress' %}" class="btn btn-default btn-sm">Back</a>
            </div>
          </div>
      </form>
    </div><!--/.nav-collapse -->

  </body>
</html>

以上のようにファイルを編集することで、
「Change Status」ボタンをクリックしてIPアドレス情報を変更することができるアプリケーションを作成することができます。

再度、簡易Webサーバを立ち上げて、ホストマシンのWebブラウザで確認してみます。

(venv_app1) [vagrant@localhost django_apps]$ python pj1/manage.py runserver 0.0.0.0:8000
http://192.168.33.15:8000/app1/ipaddress/

django_app_ipaddress_change1.png

django_app_ipaddress_change2.png

以上で簡単なWebアプリケーションを作ることができました。
ここまでは、Djangoで用意されている簡易Webサーバを使って確認してきましたが、
次回からNginxなどの実際のWebサーバにデプロイする手順を説明してます。