Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
45
Help us understand the problem. What are the problem?
@narupo

Django1.9 チートシート

環境

  • Python3
  • Django1.9.2 ~ 1.10

はじめに

チラっと見る用です。

参照

用語

  • pk ... primary key

Version

Djangoのバージョンを確認。

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

Install

Project

プロジェクトの作成。

$ django-admin startproject MY-PROJECT-NAME

Application

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

$ python manage.py startapp MY-APP-NAME
$ # TODO: プロジェクトのsettings.py:INSTALLED_APPSの編集
$ # TODO: プロジェクトのurls.pyを必要なら編集
$ # TODO: models.py編集後 → Model

Server

開発用サーバーの起動。

$ python manage.py runserver
$ python manage.py runserver 0.0.0.0:8000

Admin

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

$ python manage.py createsuperuser

Shell

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

$ python manage.py shell
$ 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サーバーへの切り替え。

# 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のポートの確認方法。

SHOW GLOBAL VARIABLES LIKE 'PORT';

Migrate

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

$ python manage.py makemigrations MY-APP-NAME
$ python manage.py migrate

SQLの確認。

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

createdb

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

$ python manage.py createdb

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

$ 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 のクラスの定義例。

from django.db import models

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

Select

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

objs = MyModel.objects.all()

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

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

存在しない場合の例外。

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

WHEREはfilterで指定。

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

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

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

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

from django.shortcuts import get_object_or_404

obj = get_object_or_404(MyModel, pk=1)

オブジェクトのリスト取得または 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にモデルを一つ挿入。

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を更新。

obj = MyModel.objects.get(pk=MY-PRIMARY-KEY)
obj.my_field = 'Update my field'
obj.save()

Delete

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

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

Validate

バリデーション。

obj.full_clean()

ForeignKey

以下のようなモデルの

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 への委譲。

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 への委譲。

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メソッド名で分岐。

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.

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 クラスを作成し、自作モデルと一緒に登録する。

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を編集する。

INSTALLED_APPS = [
...
    'django.contrib.staticfiles', # <- これが必要
...
]
STATIC_URL = '/static/' # <- これも必要

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

$ mkdir myapp/static

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

$ 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 内の設定も必要になる。

##
# 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 ファイルの設定例。

##
# 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 で指定したファイルを別のファイルで拡張してから描画することが出来る。

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

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

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

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

{% extends 'base.html' %}

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

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

comment

コメントは一行単位。

{# my_comment #}

varialble

変数の参照。

{{ my_variable }}

参照時のデフォルト値。

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

長さ。

{{ my_list|length }}

リストを添字で参照。

{{ my_list.0 }}

CSRF

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

{{ csrf_token }}

static

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

{% load staticfiles %}

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

include

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

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

パラメータ指定。

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

with

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

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

if

if-else構文。

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

比較演算。

{% if duck == 'Duck' %}
    <div>{{ duck }}</div>
{% endif %}
{% if duck|length > 0 %}
    <div>{{ duck }}</div>
{% endif %}

for

{% for obj in objs %}
    <p>{{ obj }}</p>
{% endfor %}

forloop.counterの参照。ループ中に添え字が欲しいとき。
forloop.counter0で0オリジンな添え字を得られる。

{% for obj in objs %}
    <p>{{ forloop.counter }}</p>
    <p>{{ forloop.counter0 }}</p>
{% endfor %}

Django/templateの 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 の一例。

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 のフォームで管理される。
ログイン・フォームの作成例。

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)

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)

<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
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
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
45
Help us understand the problem. What are the problem?