Python Django入門 (4)

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

Bootstrapの導入

Django で CRUD を作る説明の前に、Bootstrapの導入を行います。

我々エンジニアが作るHTMLは、デザイン的にも味気ないものとなってしまいます。

そこで、CSSフレームワークのBootstrapを使うことにします。

ドキュメントは英語ですが、実例が載っているので、やりたいことは見つかると思います。

Bootstrap

Bootstrap で必要な jQuery を含めて、以下からダウンロードします。

ダウンロードしたファイルを、mybook プロジェクト ディレクトリの下に static というディレクトリを作って、以下のように配置します。

この static というディレクトリは、mybook/settings.py の STATIC_URL で指定されたディレクトリです。

mybook/
    static/
        css/
            bootstrap-theme.css
            bootstrap-theme.css.map
            bootstrap-theme.min.css
            bootstrap-theme.min.css.map
            bootstrap.css
            bootstrap.css.map
            bootstrap.min.css
            bootstrap.min.css.map
        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
            jquery-2.2.0.min.js

static ディレクトリは、通常ですとアプリケーションの下の mybook/cms/static を探しに行きます。
今回は、プロジェクト共通として、mybook/static に js、cssを置くことにします。

ここを探してくれるよう、mybook/settings.py の最後に、STATICFILES_DIRS を追加します。

# 静的ファイルを共通で置く
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, "static"),
)

django-bootstrap-form

一覧系HTMLは、Bootstrapで必要なclassを手書きして、登録/修正のフォーム系HTMLは django-bootstrap-form という Python モジュールを使います。

インストールは、pip コマンドで行います。

python manage.py runserver で動いている時は、Ctrl + c で停止してから行ってください。
(env1) 仮想環境にいることを前提にしています。

$ pip install django-bootstrap-form

現時点では、3.2 が入りました。

$ pip freeze -l
Django==1.9.2
django-bootstrap-form==3.2

確認できたら、また python manage.py runserver で起動しておきましょう。

mybook/settings.py の INSTALLED_APPS に 'bootstrapform' を追加します。

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'bootstrapform',  # django-bootstrap-form
    'cms',
)

Django の CRUD

ビューをざっと作る

一覧、登録、修正、削除のファンクションが必要なので、`cms/views.py' にひな形を作ります。

登録、修正は編集としてひとまとめにしています。(book_idの指定がなければ登録、あれば修正)

コードスタイルとして、defの前も2行あけないと波線が出て、うるさいです。

from django.shortcuts import render
from django.http import HttpResponse


def book_list(request):
    """書籍の一覧"""
    return HttpResponse('書籍の一覧')


def book_edit(request, book_id=None):
    """書籍の編集"""
    return HttpResponse('書籍の編集')


def book_del(request, book_id):
    """書籍の削除"""
    return HttpResponse('書籍の削除')

URL スキームの設計

cms/urls.py というファイルは存在しないので、新しく作ります。

左側の cms の所で右クリックして、New > Python File で urls.py と指定します。

この中で、URLと、ビューのファンクションの紐付けを行います。

URLとファンクション名は一致させる必要はありません。このあたりは自由です。

from django.conf.urls import url
from cms import views

urlpatterns = [
    # 書籍
    url(r'^book/$', views.book_list, name='book_list'),   # 一覧
    url(r'^book/add/$', views.book_edit, name='book_add'),  # 登録
    url(r'^book/mod/(?P<book_id>\d+)/$', views.book_edit, name='book_mod'),  # 修正
    url(r'^book/del/(?P<book_id>\d+)/$', views.book_del, name='book_del'),   # 削除
]

URLは正規表現となっています。

次に、 cms/urls.py をプロジェクト全体の mybook/urls.py の中でインクルードします。

from django.conf.urls import url, include   # ←, includeを追加
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^cms/', include('cms.urls', namespace='cms')),   # ←ここを追加
]

最終的にURLは以下のようになります。

ブラウザで確認してみて下さい。

http://127.0.0.1:8000/cms/book/
http://127.0.0.1:8000/cms/book/add/
http://127.0.0.1:8000/cms/book/mod/5/
http://127.0.0.1:8000/cms/book/del/7/

一覧のビュー

一覧を表示するビューを、きちんと書いてみます。

cms/views.pydef book_list を以下のように修正します。

from django.shortcuts import render
from django.http import HttpResponse

from cms.models import Book


def book_list(request):
    """書籍の一覧"""
#    return HttpResponse('書籍の一覧')
    books = Book.objects.all().order_by('id')
    return render(request,
                  'cms/book_list.html',     # 使用するテンプレート
                  {'books': books})         # テンプレートに渡すデータ

一覧のテンプレートを作る

mybook プロジェクトの cms アプリケーションで使う book_list.html というテンプレートを作成します。

位置は、以下のようになります。

mybook/cms/templates/cms/book_list.html

その前に、これの継承元となる base.html というテンプレートを作成しましょう。

base.html は、cms以外のアプリケーションでも共通で使えるよう、templates の直下に作成します。

左側の cms を右クリックして、New > Directory で templates を指定
templates を右クリックして、New > HTML File で base.html を指定、といった感じです。

mybook/cms/templates/base.html

base.html の中身は、以下のようになります。

{% load staticfiles %}
<!DOCTYPE html>
<html lang="{{ LANGUAGE_CODE|default:"en-us" }}">
<head>
<meta charset="UTF-8">
<title>{% block title %}My books{% endblock %}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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.2.0.min.js' %}"></script>
<script src="{% static 'js/bootstrap.min.js' %}"></script>
{% block extrahead %}{% endblock %}
</head>
<body>
  <div class="container">
    {% block content %}
      {{ content }}
    {% endblock %}
  </div>
</body>
</html>

それでは、この base_html を継承して mybook/cms/templates/cms/book_list.html を作成します。

こちらは必要な所のみを書いていく形となります。

class に指定しているのは、Bootstrapで必要な class です。

{% extends "base.html" %}

{% block title %}書籍の一覧{% endblock title %}

{% block extrahead %}
<style>
table {
  margin-top: 8px;
}
</style>
{% endblock %}

{% block content %}
    <h3 class="page-header">書籍の一覧</h3>
    <a href="{% url 'cms:book_add' %}" class="btn btn-default btn-sm">追加</a>
    <table class="table table-striped table-bordered">
      <thead>
        <tr>
          <th>ID</th>
          <th>書籍名</th>
          <th>出版社</th>
          <th>ページ数</th>
          <th>操作</th>
        </tr>
      </thead>
      <tbody>
        {% for book in books %}
        <tr>
          <td>{{ book.id }}</td>
          <td>{{ book.name }}</td>
          <td>{{ book.publisher }}</td>
          <td>{{ book.page }}</td>
          <td>
            <a href="{% url 'cms:book_mod' book_id=book.id %}" class="btn btn-default btn-sm">修正</a>
            <a href="{% url 'cms:book_del' book_id=book.id %}" class="btn btn-default btn-sm">削除</a>
          </td>
        </tr>
        {% endfor %}
      </tbody>
    </table>
{% endblock content %}

それではブラウザで確認してみましょう。

http://127.0.0.1:8000/cms/book/

cms01.jpg

追加、修正のフォーム

cms/forms.py というファイルを作って、以下のように記述します。
ここでは、cms/models.py の Book モデルを追加、修正するための元となるフォームを作成します。

from django.forms import ModelForm
from cms.models import Book


class BookForm(ModelForm):
    """書籍のフォーム"""
    class Meta:
        model = Book
        fields = ('name', 'publisher', 'page', )

追加、修正のビュー

cms/views.pydef book_edit を以下のように修正します。

from django.shortcuts import render, get_object_or_404, redirect
from django.http import HttpResponse

from cms.models import Book
from cms.forms import BookForm

  :

def book_edit(request, book_id=None):
    """書籍の編集"""
#     return HttpResponse('書籍の編集')
    if book_id:   # book_id が指定されている (修正時)
        book = get_object_or_404(Book, pk=book_id)
    else:         # book_id が指定されていない (追加時)
        book = Book()

    if request.method == 'POST':
        form = BookForm(request.POST, instance=book)  # POST された request データからフォームを作成
        if form.is_valid():    # フォームのバリデーション
            book = form.save(commit=False)
            book.save()
            return redirect('cms:book_list')
    else:    # GET の時
        form = BookForm(instance=book)  # book インスタンスからフォームを作成

    return render(request, 'cms/book_edit.html', dict(form=form, book_id=book_id))

追加、修正のテンプレート

mybook/templates/base_html を継承して mybook/cms/templates/cms/book_edit.html を作成します。

{% extends "base.html" %}
{% load bootstrap %}

{% block title %}書籍の編集{% endblock title %}

{% block content %}
    <h3 class="page-header">書籍の編集</h3>
    {% if book_id %}
    <form action="{% url 'cms:book_mod' book_id=book_id %}" method="post" class="form-horizontal" role="form">
    {% else %}
    <form action="{% url 'cms:book_add' %}" method="post" class="form-horizontal" role="form">
    {% endif %}
      {% csrf_token %}
      {{ form|bootstrap_horizontal }}
      <div class="form-group">
        <div class="col-sm-offset-2 col-sm-10">
          <button type="submit" class="btn btn-primary">送信</button>
        </div>
      </div>
    </form>
    <a href="{% url 'cms:book_list' %}" class="btn btn-default btn-sm">戻る</a>
{% endblock content %}

cms/forms.py の BookForm で定義した項目を、cms/views.py で form という変数でテンプレートに渡し、{{ form }} と書くと、フォームの内容がHTMLで展開されます。

ここではさらに、{{ form|bootstrap_horizontal }} として、Bootstrapの書式に変換しています。

書籍の登録ページは、以下のようになります。

cms02.jpg

削除のビュー

cms/views.pydef book_edit を以下のように修正します。

def book_del(request, book_id):
    """書籍の削除"""
#     return HttpResponse('書籍の削除')
    book = get_object_or_404(Book, pk=book_id)
    book.delete()
    return redirect('cms:book_list')

それでは、書籍の一覧ページから「削除」ボタンを押して、書籍を削除してみてください。

cms01.jpg

いきなり消していますが、本当は Bootstrap の モーダルダイアログを出して、確認メッセージを出した方がいいでしょう。
これは後に取り組むこととします。

Python Django入門 (5) に続きます。