Django : Tips

Last Change: 29-Mar-2016.
author : qh73xe

このページでは Django での細かい Tips をメモしていきます.

Djangoのバージョンを調べる

Django は現在も開発が行われているライブラリですので, 当然仕様の変更があります.

しかし,日本語化されているチュートリアルが最新のものに対応しているとは限りません. そのため,日本語の説明にない機能,変更された機能にハマり,困ることがあるかもしれません.

このような際,とりあえず,システムに導入されている Django のバージョンを確認する 必要があります.

django のバージョン確認
1
2
>>> import django
>>> django.get_version()

静的なファイルを利用する

警告

Django のバージョン注意

このやり方は Django 1.7 の時に有効だったやり方です. 1.8 では上手く行かないので注意してください

Django と javascript や CSS と連携するにはひと工夫必要です. setting.py で STATIC_URL の設定を行い,url.py でマッピングを行い,htmlファイルに反映する必要があります.

setting.py
1
2
3
4
5
6
7
import os
from os.path import abspath, dirname
SITE_ROOT = abspath(os.path.join(dirname(__file__), ".."))   # プロジェクトのルートをSITE_ROOTとする
STATIC_URL = '/static/'  # 静的ファイルを保存するフォルダ名を設定
STATICFILES_DIRS = (    # 静的ファイルを保存するフォルダのパスを設定
    os.path.join(SITE_ROOT, '_static'),
)
urls.py
1
2
3
4
5
6
7
from django.conf.urls import patterns, include ,url
from django.contrib.staticfiles.urls import staticfiles_urlpatterns  # これを追加

urlpatterns = patterns('',
    ...
)
urlpatterns += staticfiles_urlpatterns()  # これも追加

上記の 2 つを記述し終えたら,html から静的ファイルを呼び出します.

sample.html
1
<link href="{{ STATIC_URL }}css/bootstrap.min.css" rel="stylesheet" >

で, view.py で表示する際には,RequestContext でレタリングを行う必要があります.

view.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from django.shortcuts import render_to_response
from django.template import RequestContext


def sample(request):
    return render_to_response(
        'sample.html',
        {'title':"タイトル"},
        context_instance = RequestContext(request)
    )

Django 1.8 の場合

最近の Django では上記の設定は少し変更されたようです. 具体的には setting.py のTEMPLATES の OPTIONS の項目を以下のようにする必要があります.

seting.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
 TEMPLATES = [
     {
         'BACKEND': 'django.template.backends.django.DjangoTemplates',
         'DIRS': [
             os.path.join(BASE_DIR,  'templates')
         ],
         'APP_DIRS': True,
         'OPTIONS': {
             'context_processors': [
                 'django.template.context_processors.debug',
                 'django.template.context_processors.request',
                 'django.contrib.auth.context_processors.auth',
                 'django.contrib.messages.context_processors.messages',
                 'django.template.context_processors.static',
             ],
         },
     },
 ]

ログイン,ログアウト設定を行う

アプリケーションを作成している際にログイン,ログアウトの設定を行いたい場合はよくあることかと思います. 基本的に django の良い所はこの手の煩雑な処理を省略できるところにあるかと思います.

ログイン,ログアウト用の設定は実は最初から組み込まれており, あとは,必要に応じてテンプレートを設定するだけです.

私の場合,user モデル(アカウント用のDB設定だと思ってくれればよいです)を 拡張したい場合が多いので,先に accounts という app を作成してしまい, url の指定を行ってしまうことが多いです.

urls.py
1
2
3
4
 url(r'^accounts/login/$', 'django.contrib.auth.views.login',
     {'template_name': 'accounts/login.html'}),
 url(r'^logout/$', 'django.contrib.auth.views.logout',
     {'template_name': 'accounts/logged_out.html'}),

その上で, accounts/templates/acounts にテンプレートを作成します. とりあえず,最低限のものを以下に記述します.

accounts/templates/accounts/login.html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
{% extends "base.html" %}
{% block content %}
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}

<form method="post" action="{% url 'django.contrib.auth.views.login' %}">
{% csrf_token %}
<div class="form-group">
    {{ form.username.label_tag }}
    {{ form.username }}
</div>
<div class="form-group">
    {{ form.password.label_tag }}
    {{ form.password }}
</div>
<input type="submit" class="btn btn-primary btn-lg" value="login" />
<input type="hidden" name="next" value="{{ next }}" />

</form>
{% endblock %}
accounts/templates/accounts/logged_out.html
1
2
3
4
5
{% extends "base.html" %}
{% block title %}ログアウト{% endblock title %}
{% block jumb %}
    <h3 class="page-header">ログアウトしました</h3>
{% endblock %}

出力に Json を返す

アプリケーションによっては,保持している BD の情報を適当に操作して json で返す必要があるかもしれません. というか,こうしておくと適当な API を簡単に作れるので何かと便利です.

django には serializers という機能があり,上記の作業を大変楽にしてくれます. 例えば,hoge という app で管理をしている foo というデータをすべて Json に変換し ,表示するには以下のようにします.

views.py
1
2
3
4
5
6
7
 def return_json_demo(request):
     from django.http import HttpResponse
     from django.core import serializers
     from hoge.model import foo

     json = serializers.serialize('json', foo, fields=__all__, ensure_ascii=False)
     return HttpResponse(json)

form に CSS/Class を指定する

django を使用する際, From の class を指定できたほうが便利な瞬間があります.

  • 例えば, Bootstrap を使用している時など
    • 個人的に Djnago のためのライブラリとかやってられなくなるので直書きが好きです.

form の作成時に個別に class を指定しても良いのですが, 以下のような継承関係を使用すると記述量は一気に減るかと思います.

forms.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class BaseForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super(BaseForm, self).__init__(*args, **kwargs)
        for field_name, field in self.fields.items():
            field.widget.attrs['class'] = 'form-control'

 class HogeForm(BaseForm):
     class Meta:
         model = ...

リダイレクトを利用する

場合によっては、ある関数を実行させた後に別のページに飛ばしたいことがあるかもしれません。 このような作業を リダイレクト といいます。

Django でこれを行う場合 HttpResponseRedirect 関数と reverse 関数を利用するのが便利です。 HttpResponseRedirect 関数がリダイレクトの作業を行う関数で、 reverse 関数は、 あるキーワードから、該当する url を特定するものです。

例えば以下のような urls.py が存在するとします。

urls.py
1
2
url(r'^home/$', views.home,name='home'),
url(r'^add/', views.add, name='add'),

この name 属性を使って、 url を特定する関数が reverse 関数です。 view 内 で使用するには以下のようにします。

views.py
1
2
3
4
5
6
7
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse

def add(request):
    <何らかの処理>

    return HttpResponseRedirect(reverse('home'))

このようにすることで add 関数の処理が実行されたあとに ‘/home/’ に移動させることができます。

Django with sqlite3 で save の挙動を早くする

警告

この項目に関して

先に注意というかお詫びをしておくと, この Tips の内容に関して私は完全に理解をしているわけではありません. ただ,こうすると早くなるよという報告に過ぎないと思ってください.

Django でデータベースの操作を行う際,sqlite3 を使用していて, 大量のデータ(それでも 1万程度ですが)をまとめて save しようとすると 妙に処理に時間がかかる時があります.

これはバックグラウンドで走る sqlite3 が Insert を行う際に,トランザクションをしているかららしいです.

で妙に重いな−と思った場合以下のようにすると 処理が早くなったりします.

from django.db import transaction

@transaction.atomic
def viewfunc(request):
    # 何か適当な処理
    ...
    a.save()

注釈

transaction.atomic に関して

この関数は Djnago1.7 以上のものです(確か,1.7 で変更があったはず). それ以前のヴァージョンでは別の関数が用意されているらしいので注意してください.

一応, 公式サイトを見る限り sqlite3 に関して SELECT, INSERT, UPDATE, DELETE, REPLACE の処理すべてが atomic 関数で効果があるようです.

https://docs.djangoproject.com/en/1.8/topics/db/transactions/

Django で作成したアプリケーションをネイティブアプリにする

しばしば、 Django で作成した web アプリをネイティブアプリにしたいことがあります。 単純に、 ブラウザのもともとあるボタンがうるさかったり、ローカルアプリと連携をしたくなったりする場合です。

このような場合 pyside を利用するととても簡単にネイティブアプリ化が可能です。 詳しくは ../pyside/qWebView に書いてあるので ここではサンプルコードのみを紹介します。

run.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from subprocess import Popen
from time import sleep
from sys import argv, exit
from PySide.QtCore import QUrl
from PySide.QtGui import QApplication
from PySide.QtWebKit import QWebView


def closeEvent(self, event):
    self.web.kill()
    event.accept()

if __name__ == "__main__":
    cmds = ['python', 'manage.py', 'runserver']
    web = Popen(cmds)
    sleep(5)

    app = QApplication(argv)
    app.web = web
    app.closeEvent = closeEvent
    web_view = QWebView()
    web_view.load(QUrl('http://127.0.0.1:8000/'))
    web_view.show()
    exit(app.exec_())

ここでは ローカル でデバック用の djnago を起動させて、それをネイティブアプリとして実行しています。 色のついている行はこのようにデバック用の Django を起動させているための処理です。 実際にサーバーで公開しているプロジェクトをネイティブ用にしたい場合、 22 行目以外の色のついている行を削除し、 22 行目の url をアプリケーションの url に変更すればよいです。

この機能はかなり単純なスクリプトで動くので結構便利かと思います。