Django
Python3

Django1.9 チートシート


環境


  • Python3

  • Django1.9.2 ~ 1.10


はじめに

チラっと見る用です。


参照


用語


  • pk ... primary key


Version

Djangoのバージョンを確認。


version

$ python -c "import django; print(django.get_version())"



Install


Project

プロジェクトの作成。


project

$ django-admin startproject MY-PROJECT-NAME



Application

アプリケーションの作成。


app

$ python manage.py startapp MY-APP-NAME

$ # TODO: プロジェクトのsettings.py:INSTALLED_APPSの編集
$ # TODO: プロジェクトのurls.pyを必要なら編集
$ # TODO: models.py編集後 → Model


Server

開発用サーバーの起動。


server

$ python manage.py runserver

$ python manage.py runserver 0.0.0.0:8000


Admin

管理サイトのスーパーユーザーを作成。


admin

$ python manage.py createsuperuser



Shell

Django のインタラクティブな操作。

設定中の DB を Django から操作出来る他、各ライブラリの動作確認も出来る。


shell

$ python manage.py shell



example

$ python manage.py shell

>>> from MY-APP-NAME.models import MyModel
>>> MyModel.objects.all()
[]
>>> m = MyModel()
>>> m.save()
>>> m.id
1
>>>



DB


MySQL

settings.py のMySQLサーバーへの切り替え。


settings.py

# Database

# https://docs.djangoproject.com/en/1.9/ref/settings/#databases

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'MY-DB-NAME',
'USER': 'MY-DB-USER',
'PASSWORD': 'MY-DB-PASSWORD',
'HOST': '127.0.0.1',
'PORT': '3306',
}
}


MySQLのポートの確認方法。


mysql

SHOW GLOBAL VARIABLES LIKE 'PORT';



Migrate

更新とDBへの適用。Modelを追加したら行う。


migrate

$ python manage.py makemigrations MY-APP-NAME

$ python manage.py migrate

SQLの確認。


sqlmigrate

$ python manage.py sqlmigrate MY-APP-NAME 0001



createdb

DBの作成。settings.pyでSQLiteを使っている場合はSQLiteに構築される。


createdb

$ python manage.py createdb


--noinputオプションで対話モードに入らず自動設定。


createdb

$ python manage.py createdb --noinput



Model


Field

 Field のタイプは https://docs.djangoproject.com/en/1.9/ref/models/fields/#model-field-types を参照。

 各 Field は Field クラス (https://docs.djangoproject.com/en/1.9/_modules/django/db/models/fields/#Field) を継承している。Field クラスのコンストラクタは以下の仮引数を取る。

def __init__(self,

verbose_name=None,
name=None,
primary_key=False,
max_length=None,
unique=False,
blank=False,
null=False,
db_index=False,
rel=None,
default=NOT_PROVIDED,
editable=True,
serialize=True,
unique_for_date=None,
unique_for_month=None,
unique_for_year=None,
choices=None,
help_text='',
db_column=None,
db_tablespace=None,
auto_created=False,
validators=[],
error_messages=None
):

 フィールドの一覧。


  • AutoField

  • BigIntegerField

  • BinaryField

  • BooleanField

  • CharField

  • CommaSeparatedIntegerField

  • DateField

  • DateTimeField

  • DecimalField

  • DurationField

  • EmailField

  • FileField

  • FilePathField

  • FloatField

  • ImageField

  • IntegerField

  • GenericIPAddressField

  • NullBooleanField

  • PositiveIntegerField

  • PositiveSmallIntegerField

  • SlugField

  • SmallIntegerField

  • TextField

  • TimeField

  • URLField

  • UUIDField

  • ForeignKey

  • ManyToManyField

  • OneToOneField


Class

 models.py のクラスの定義例。


models.py

from django.db import models

class Person(models.Model):
name = models.CharField(max_length=128)



Select

DBからモデルのオブジェクトを全て取得。


all

objs = MyModel.objects.all()


pkを指定してオブジェクトを取得。


get

obj = MyModel.objects.get(pk=MY-PRIMARY-KEY)


存在しない場合の例外。


exception

try:

obj = MyModel.objects.get(pk=MY-PRIMARY-KEY)
except MyModel.DoesNotExist:
pass

WHEREはfilterで指定。


filter

objs = MyModel.objects.filter(name='myname').all()


rawクエリーとリスト内包記法。objects.all() と等価。


raw

objs = [obj for obj in User.objects.raw('SELECT * FROM myapp_user')]


オブジェクトの取得または 404 例外の送出。


get_object_or_404

from django.shortcuts import get_object_or_404

obj = get_object_or_404(MyModel, pk=1)


オブジェクトのリスト取得または 404 例外の送出。


get_list_or_404

from django.shortcuts import get_list_or_404

objs = get_list_or_404(MyModel)
objs = get_list_or_404(MyModel.objects.order_by('-pub_date'))[:5]



Insert

DBにモデルを一つ挿入。


insert

obj = MyModel()

obj.id # -> None
obj.save()
obj.id # -> Number of id

obj = MyModel.objects.create(
name='my name',
age=101,
)
obj.id # -> Number of id



Update

挿入済みのモデルからDBを更新。


update

obj = MyModel.objects.get(pk=MY-PRIMARY-KEY)

obj.my_field = 'Update my field'
obj.save()


Delete

DBからモデルを一つ削除。


delete

obj = MyModel.objects.get(pk=MY-PRIMARY-KEY)

obj.delete()


Validate

バリデーション。


validate

obj.full_clean()



ForeignKey

以下のようなモデルの


models.py

class Parent(models.Model):

name = models.CharField(default='my name is parent', max_length=32)

class Child(models.Model):
parent = models.ForeignKey(Parent, on_delete=models.CASCADE)


リレーション周りの操作。

parent = Parent()

parent.save()

c = parent.child_set.create() # Parent から Child の作成
c.parent.id # Child から Parent の ID を参照
parent.child_set.all() # Parent から関連する全ての Child を取得
parent.child_set.count() # Parent から関連する Child 数を返す


urls.py

プロジェクトからアプリケーションの urls.py への委譲。


myprj/urls.py

from django.conf.urls import include, url

from django.contrib import admin

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

# myappに委譲
url(r'^myapp/', include('myapp.urls')),
]


アプリケーションからアプリケーションの views.py への委譲。


myapp/urls.py

from django.conf.urls import url 

from . import views

urlpatterns = [
# views.py 内の index 関数に委譲。name は名前空間を表し、template ファイル内の {% url 'namespace' %} などで参照される。
url(r'^', views.index, name='index'),
]



views.py

HTTPメソッド名で分岐。


method_test

from django.http import HttpResponse

def method_test(request):
if 'GET' in request.method:
return HttpResponse('Success to GET')

elif 'POST' in request.method:
return HttpResponse(status=200)

else:
return HttpResponse(status=501)


templateの描画。パスのオリジンは MY-APP-NAME/templates.


render_test

from django.shortcuts import render

from django.http import HttpResponse

def render_test(request):
if 'GET' in request.method:
return render(request, 'MY-APP-NAME/MY-TEMPLATE-FILE-NAME', {
'title': 'Render Test',
})

else:
return HttpResponse(status=501)



admin.py

 参照: https://docs.djangoproject.com/ja/1.9/ref/contrib/admin/actions/

 /admin 管理画面で自作モデルを管理したい場合は admin.py を編集する。自作モデルと ModelAdmin を継承した自作モデル用の Admin クラスを作成し、自作モデルと一緒に登録する。


admin.py

from django.contrib import admin

from .models import User

class UserAdmin(admin.ModelAdmin):
list_display = ('id', 'name', 'modified')

admin.site.register(User, UserAdmin)



Static

JSライブラリやCSS、画像ファイルなど。DjangoはCDNもサポートしている。


開発用サーバーの場合

MY-PROJECT-NAME/setting.pyを編集する。


setting.py

INSTALLED_APPS = [

...
'django.contrib.staticfiles', # <- これが必要
...
]


setting.py

STATIC_URL = '/static/' # <- これも必要


作成したアプリにstaticディレクトリを加える。


case-of-linux

$ mkdir myapp/static


ここでネームスペース用のディレクトリが必要になる。慣例でアプリ名のディレクトリを作成する。


case-of-linux

$ mkdir myapp/static/myapp


これでhttp://localhost:8000/static/myapp/file.txt等でアクセス出来る。


本番動作時の場合

 本番動作では Apache2 と WSGI モジュールを使いコンテンツをネットに公開する。ディストロごとに環境依存の手順がある。

 参照: How to deploy with WSGI

 開発環境も含めると、Djangoのコンテンツの公開方法は3通り以上あるらしい。

 1. 開発サーバーによる公開(python manage.py runserver 0.0.0.0:80 等)

 2. Apache2 + WSGI による公開 

 3. Apache2 + WSGI + ファイルサーバー(nginx 等)による公開

 1. は開発時の公開方法。公開にあたって 2. または 3. の方法を選択する必要がある。

 また、本番動作時では setting.py 内の設定も必要になる。


setting.py

##

# DEBUG が False の時、開発用サーバーにディティールは表示されず、ALLOWED_HOSTS の設定が参照される。
# また、Django は static ファイルの管理をしなくなる。static ファイルをネットに公開するには、VirtualHost にエイリアスを設定するか、ファイルサーバーを立てる必要がある。
# VirtualHost のエイリアス設定は https://docs.djangoproject.com/ja/1.10/howto/deployment/wsgi/modwsgi/ を参照。
# Django を Apache2 + wsgi で動かす場合、開発者は開発用サーバーを使用しないのでこの値は False に設定されるだろう。
# この時、static ファイルの運用方法も決定されている必要がある。
#
DEBUG = True

ALLOWED_HOSTS = ['*'] # DEBUG が False のとき参照される



Static

 static ファイルの設定例。


setting.py

##

# STATIC_URL は template の {% static 'my/file.html' %} などのタグで使用される。
# STATIC_URL が '/static/' の場合、 タグは 'http://localhost/static/my/file.html' などに変換される。
# STATIC_URL が 'http://localhost:8080/static' の場合、タグは 'http://localhost:8080/static/my/file.html' などに変換される。
#
STATIC_URL = '/static/'

##
# STATIC_ROOT は collectstatic の収集ファイルのぶちまけ先。
# ファイルシステム上のパスを記述する。
# STATIC_ROOT が '/tmp/mystatic/' の場合、collectstatic は /tmp/mystatic/ ディレクトリ内にファイルを集める。
# このディレクトリはただの収集ファイルの格納先であり、Django はこれを管理・使用しない。
# STATICFILES_DIRS も参照のこと。
#
STATIC_ROOT = os.path.join(BASE_DIR, 'static') # プロジェクト直下の static ディレクトリをルートに指定

##
# STATICFILES_DIRS は、collectstatic の収集元のディレクトリを記述する。
# os.path.join(BASE_DIR, 'myapp/static') が追加されていた場合、collectstatic は myapp/static ディレクトリ以下からファイルを収集する。
#
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'myapp/static'), # myapp 以下の static ディレクトリを収集する
]



Template

Djangoのtemplate.


extends

拡張。Django/template では extends で指定したファイルを別のファイルで拡張してから描画することが出来る。


tree

myprj/                     # Project Root

myapp/ # Application Root
templates/ # Application template files
base.html # Base html for the extend
myapp/ # Application namespace
index.html # Extends file from here

拡張のベースとなるファイル。


base.html

<!DOCTYPE html>

<html>
<head>
<title>myprj - {% block title %}{% endblock %}</title>
</script>
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>


拡張例。 block ~ endblock を使うことでベースファイルに指定の文字列を流し込める。例ではベースファイルの block titleblock content に文字列を流し込んで拡張している。


index.html

{% extends 'base.html' %}

{% block title %}My title{% endblock %}

{% block content %}
<h1>Hello, World!</h1>
{% endblock %}



comment

コメントは一行単位。

{# my_comment #}


varialble

変数の参照。


var

{{ my_variable }}


参照時のデフォルト値。


var-with-default

{{ my_variable|default:'This is default value' }}


長さ。


length

{{ my_list|length }}


リストを添字で参照。


index

{{ my_list.0 }}



CSRF

CSRFトークンの参照。通信周りで使う。


csrf

{{ csrf_token }}



static

staticファイルの読み込みとパスの参照。前述のStaticも参照のこと。


static

{% load staticfiles %}

{% static 'myapp/jquery.min.js' %}
{% static 'myapp/style.css' %}
{% static 'myapp/image.png' %}



include

パスはMY-APP-NAME/templates/がオリジン。


include

{% include 'myapp/template.html' %}


パラメータ指定。


include

{% include 'myapp/template.html' with title='The Title' message='Hello' %}



with

スコープ付きのエイリアス。


with

{% with 'myapp/template.html' as fname %}

{% include fname %}
{% endwith %}


if

if-else構文。


if-else

{% if duck %}

<div>{{ duck }}</div>
{% else %}
<div>Nothing...</div>
{% endif %}

比較演算。


if-eq

{% if duck == 'Duck' %}

<div>{{ duck }}</div>
{% endif %}


if-compare

{% if duck|length > 0 %}

<div>{{ duck }}</div>
{% endif %}


for


for

{% for obj in objs %}

<p>{{ obj }}</p>
{% endfor %}

forloop.counterの参照。ループ中に添え字が欲しいとき。

forloop.counter0で0オリジンな添え字を得られる。


for

{% for obj in objs %}

<p>{{ forloop.counter }}</p>
<p>{{ forloop.counter0 }}</p>
{% endfor %}

Django/templateの for 構文では rangeをサポートしていない。

代価えとしてリストを使う。


for-range

'mylist': range(0, 10),

...

{% for el in mylist %}
{% endfor %}



template tags

 template タグの自作。

 参照: https://docs.djangoproject.com/ja/1.9/howto/custom-template-tags/

 

 アプリのディレクトリ直下に templatetags ディレクトリを作成し、そこにタグのファイルを放る。

$ mkdir myapp/templatetags

$ vi myapp/templatetags/mytag.py

 タグは用途ごとに分別されているっぽい。以下は assignment_tag の一例。


mytag.py

from django import template

register = template.Library()

@register.assignment_tag
def my_ass_tag():
return {'message': 'This is ass******* tag.'}


 テンプレートファイル内での使用例。

{# 読み込み #}

{% load mytag %}

{# assignment_tag を使う #}
{% my_ass_tag as data %}

{{ data.message }}


Form

 フォーム。

 参照: https://docs.djangoproject.com/en/1.9/topics/forms/

 モデルからフォームを作成する場合: https://docs.djangoproject.com/en/1.11/topics/forms/modelforms/

 Django ではフォームの作成をサポートしている。フォームを使うとバリデーションや HTML のコーディング量軽減が可能になる。

 フォームを使うにはまず myapp/forms.py に自作フォームを定義する。そして views.py で POST/GET に応じてバリデーションなどを行い、template にフォーム・オブジェクトを渡すことでフォームの描画を補助する。フォームのデータは一連の処理の間 myapp/forms.py のフォームで管理される。

 ログイン・フォームの作成例。


forms.py

from django import forms

class LoginForm(forms.Form):
username = forms.CharField(label='User name', max_length=128)
password = forms.CharField(label='Password', widget=forms.PasswordInput)



views.py

from .forms import LoginForm

def myview(request):
if request.method == 'GET':
# フォームの描画
return render(request, 'myapp/my-template.html', {
'form': LoginForm()
})

elif request.method == 'POST':
# POSTメソッドで送られてきたフォームデータを取得
form = LoginForm(request.POST)
if not form.is_valid():
raise RuntimeError('フォームのデータが不正')

# バリデート済みのフィールドを取得
username = form.cleaned_data['username']
password = form.cleaned_data['password']
# 何かの処理

form.save(commit=False)



my-template.html

<form action="/my-form" method="POST">

{% csrf_token %}
{{ form }}
<input type="submit" value="送信">
</form>

<form action="/my-form" method="POST">
{% csrf_token %}
{{ form.username.label }}: {{ form.username }}<br>
{{ form.password.label }}: {{ form.password }}<br>
<input type="submit" value="送信">
</form>



Auth

 認証システム。

 参照: https://docs.djangoproject.com/ja/1.9/ref/contrib/auth/


User

 認証システムの認証ユーザーはモデル User で管理される。現在の認証ユーザーの一覧。

from django.contrib.auth.models import User

users = User.objects.all()
print(users)

 User オブジェクトのパブリックな属性一覧。

DoesNotExist

Meta
MultipleObjectsReturned
REQUIRED_FIELDS
USERNAME_FIELD
backend
check
check_password
clean
clean_fields
date_error_message
date_joined
delete
email
email_user
first_name
from_db
full_clean
get_all_permissions
get_deferred_fields
get_full_name
get_group_permissions
get_next_by_date_joined
get_previous_by_date_joined
get_session_auth_hash
get_short_name
get_username
groups
has_module_perms
has_perm
has_perms
has_usable_password
id
is_active
is_anonymous
is_authenticated
is_staff
is_superuser
last_login
last_name
logentry_set
natural_key
normalize_username
objects
password
pk
prepare_database_save
refresh_from_db
save
save_base
serializable_value
set_password
set_unusable_password
unique_error_message
user_permissions
username
username_validator
validate_unique


Create

 認証ユーザーの作成と保存。

from django.contrib.auth.models import User

user = User.objects.create_user('ono', 'lennon@thebeatles.com', 'onopassword')
user.last_name = 'Yoko'
user.save()


Update

 認証ユーザーの更新と保存。

from django.contrib.auth.models import User

user = User.objects.get(username='ono')
user.set_password('new password')
user.save()


Authenticate and Processing

 Authenticate(認証する)と分岐処理。

from django.contrib.auth import authenticate

user = authenticate(username='ono', password='secret')
if user is not None:
# 認証に成功
else:
# 認証に失敗


Permission

 認証ユーザーはデータへのアクセス権限を持つ。権限はモデル Permission で定義される。各モデルにはデフォルトで add, change, delete の権限が用意される。

from django.contrib.auth.models import Permission

perms = Permission.objects.all()
print(perms)


has_perm

 ユーザーが特定のモデルに対して add, change, delete の権限を持っているかどうかは has_perm() で確認できる。Foo アプリケーションのモデル Bar について確認する場合は下記のように書式を渡して真偽値を取る。

user.has_perm('foo.add_bar') # ユーザーが Foo アプリの Bar モデルに add 権限を持つなら True

user.has_perm('foo.change_bar')
user.has_perm('foo.delete_bar')


Create, Add, Remove

 ユーザーに権限を付与する場合は、まず Permission で権限を取得するか作成する。その権限を user.user_permissions.add(Permission) でユーザーに付与する。

 Django はデフォルトで add, change, delete の権限をモデルに合わせて DB のテーブル auth_permission に作成するので、これらの権限については DB から取得できる。付与した権限をオブジェクトに反映させたい場合は、DB からユーザーを再取得する必要がある。

from django.contrib.auth.models import User, Permission

user = User.objects.get(username='ono')

# ono の Foo アプリケーションの Bar モデルに対する change の権限は
print(user.has_perm('foo.change_bar'))

# Bar モデルへの change 権限を取得後、ユーザーに付与する
perm = Permission.objects.get(codename='change_bar')
user.user_permissions.add(perm)

# 権限を再確認するが False
print(user.has_perm('foo.change_bar'))

# 権限を付与したら DB からオブジェクトを再取得(fetch)する
user = User.objects.get(pk=user.id)
print(user.has_perm('foo.change_bar'))

# 権限の剥奪は user_permissions.remove(Permission) を使う
user.user_permissions.remove(perm)
user = User.objects.get(pk=user.id)
print(user.has_perm('foo.change_bar'))


User's permissions

 ユーザーの権限一覧。

perms = user.get_all_permissions()

print(perms)

perms = user.user_permissions.all()
print(perms)


In views.py

 views.py で認証ユーザーを判別する。

def example_view(request):

if request.user.is_authenticated:
# このユーザーは認証済み
else:
# このユーザーは未認証


ImageField

ImageFieldを使うにはMEDIAの設定が必要。


myprj/setting.py

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

MEDIA_URL = '/media/'



myprj/urls.py

from django.conf import settings

from django.conf.urls.static import static

...

urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)



Test

テストを書く。

$ vi myapp/tests.py


tests.py

from django.test import TestCase

class MyTest(TestCase):

def my_method(self):
self.assertEqual(0, 0)


全テストの実行。

$ python3 manage.py test

アプリのテスト。

$ python3 manage.py test myapp

アプリのクラスをテスト。

$ python3 manage.py test myapp.tests.MyTest

アプリのクラスのメソッドをテスト。

$ python3 manage.py test myapp.tests.MyTest.my_method