djangoproject.com
django/django - github.com
Django documentation - docs.djangoproject.comDjango at a glance - docs.djangoproject.com - 概要、ここ見とけばだいたいわかる
Contents - docs.djangoproject.com
API Reference - docs.djangoproject.com
Python のデファクトスタンダードな WEB アプリフレームワーク。Laravel や Rails などと比較されるリッチめなフレームワークで Youtube, Dropbox, Instagram などが代表例。MVC ではなく MVT - Model / Template / View というデザインになっていて View がプレゼンテーション層 ( どんな風に提供するか? ) を決めるコントローラ的役割 を担い、Template がいわゆるビューテンプレートという考え方。
フレームワークとしては「フルスクラッチ」とは言うものの、一般的な WEB サイト / アプリに寄せた便利機能や API は殆どない。暗黙知が少なく、ピュアな Python モジュールの集合で構成されつつ、本格的な WEB システムを構築するのに最低限な API 群とルールが提供されている ... といった感じ。
はじめての Django アプリ作成 - docs.djangoproject.com
プロジェクトと再利用可能アプリ - docs.djangoproject.com
Docker 環境でのインストール手順は yano3nora/djangdock を参照。
Django はアプリケーションの管理用 CLI ツールとして django-admin ( 管理者権限コマンドツール ) と、manage.py ( その他なんでも ) を提供している。プロジェクトの作成やマイグレーション、シェルの起動など開発では様々な操作をこの CLI から行う。
Django のディレクトリ / ファイル構成は Project 配下に再利用可能な Application を複数個入れ込んでいくことが可能な立て付けになっている。以下は django-admin startproject django .
したのち python manage.py startapp app
して開発を進めた一般的な構成例。また Django は静的ファイル ( いわゆる public
とか html
ディレクトリ ) の扱いが独特 ... Django staticファイル まとめ を参照のこと。
/
manage.py
static/ デプロイ時の collectstatic 先になる
django/ ここが django プロジェクトの管理アプリ的な感じになる
__init__.py
settings.py
urls.py
wsgi.py
app/
__init__.py
admin.py
migrations/
__init__.py
0001_initial.py
models.py
static/
app/ collectstatic 時の名前衝突防止のため入れ子にする
images/
background.gif
style.css
templates/
app/ settings.py 設定の際に衝突するためここも入れ子に
detail.html
index.html
results.html
tests.py
urls.py
views.py
# models / views を分ける場合は大体こんな感じみたい
# models/
# __init__.py < from .models.user import User ...
# user.py
# views/
# __init__.py < from .views.user_view from UserView ...
# user_view.py
Django はデフォルトで、ユーザモデルとして django.contrib.auth モジュール内の django.contrib.auth.models.User を利用している。このモデルについて多くの認証系 API が用意されており、デフォルトのままでも十分使えるのだが、後でカスタムしたくなったときのために プロジェクトスタート時にカスタム User モデルを用意する ことが推奨される。
但し、認証モデルを User に絞り、これに Blongs To するロジックフルな Author みたいなモデルをぶら下げる設計の場合はこの限りではない。このへんは設計によるが、認証系はシンプルな User で一元管理して、フィールドが異なったり、ロジックをたくさん持つ Admin / Authoer / Manager / User とかは別モデルにした方が好み。いずれにせよ保険的に AbstractUser の拡張クラスは作っておいて損はない。
# settings.py
AUTH_USER_MODEL = 'myapp.MyUser'
# myapp/models.py
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
pass
# admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import User
admin.site.register(User, UserAdmin)
ipython をインストールした方がよき。
$ pip install ipython
$ python manage.py shell
> exit
# 大体これでリロードできる
> %load_ext autoreload
> %autoreload 2
$ python manage.py shell
> from django.core.cache import cache
> cache.clear()
Django でよく利用する python の Docker は sendmail ちゃん入ってなくて送信できない。sendmail のインストールや立ち上げ、Docker からのメール送信はしんどいうえに意味があんまりないので、開発中はコンソールで確認するか、例によって Gmail で適当なアカウント作って SMTP 踏み台に使うのが楽。
# settings.py
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# 'django.core.mail.backends.console.EmailBackend'
# メールを送信せずにコンソール出力する場合は上記だけで OK
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = '[email protected]'
EMAIL_HOST_PASSWORD = 'your-password-here'
EMAIL_USE_TLS = True
# 送信テスト
from django.core.mail import send_mail
send_mail('Subject', 'Message Body', '[email protected]', [
'[email protected]',
'[email protected]',
])
- [Python] Django ログ出力のまとめ
- デフォルトの設定は DEFAULT_LOGGING のようになってる
settings.py
設定とアプリサーバ側の設定を調整する必要ある
# import the logging library
import logging
# Get an instance of a logger
logger = logging.getLogger(__name__) # モジュール名をつける慣例
logger.error('Something went wrong!')
# Log level
logger.debug()
logger.info()
logger.warning()
logger.error()
logger.critical()
以下で HTTP アクセスについて HTTPS へ強制リダイレクトを実施できる。Nginx などでリバースプロキシを行っているような場合は無限リダイレクトの可能性があるので注意。
# settings.py
SECURE_SSL_REDIRECT = True
X-Forwarded-Proto - developer.mozzila.org
SECURE_PROXY_SSL_HEADER
Nginx でリバースプロキシ → アプリサーバ → django に流すようなケースでは、プロキシが 443 (HTTPS) で受けたリクエストを HTTP でアプリサーバに転送するため そのリクエストがセキュアだったか を判定するのに工夫が必要になる。
具体的には、前段でリクエストを受けるリバースプロキシ or ロードバランサーが X-Forwarded-Proto
ヘッダを付与し、後段のアプリサーバに読ませるという手法がデファクトスタンダードになっている。
django では SECURE_PROXY_SSL_HEADER
定数で 前段のプロキシから渡された SSL ヘッダを信頼する 設定を行う。
# settings.py
# リクエストを受けた際に、X-Forwarded-Proto ヘッダで
# 「さっきまでこのリクエストは https でした」って言われたら信頼する
#
# この設定をすることで、当然ユーザからの生リクエストでヘッダ偽装されたとき危険になる
# リバースプロキシ構成でのみ設定すること
#
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
Django は多くの標準機能 / API をモジュールとして提供している。インストールされているアプリは settings.py > INSTALLED_APPS
にて確認。
from django.conf import settings
if settings.DEBUG:
# Do something
from django.utils import timezone
utc_now = timezone.now() # utc
local_now = timezone.localtime() # local
start_time = timezone.localtime()
end_time = start_time + timezone.timedelta(minutes=10)
# モデルの created_at をビュー以外で出す時とか
print(timezone.localtime(user.created_at))
django.contrib.auth におけるユーザ認証 Auth の構成要素は以下。OAuth やログイン試行数の制限などより高度なものはさーどぱーちーのライブラリ使えやボケって Django さんは仰っている。
- User: User モデル
- Permission: ユーザが特定のタスクを実行できるかどうかを指定するバイナリ ( yes/no ) フラグ
- Group: 複数のユーザーにラベルとパーミッションを付与する一般的な方法
- Hash: 設定変更可能なパスワードハッシュシステム
- View/Form Template: ユーザーログインのためのフォームやビューツール
- Backend: プラガブルなバックエンドシステム
既に標準モジュール django.contrib.admin をインストールしているなら /admin
からユーザのこねこねが可能。
# Create super user for django.contrib.auth.
$ python manage.py createsuperuser --username=joe [email protected]
例によってパスワードはハッシュ保存/照合方式。パスワードのセットには User.set_password
を利用。
$ python manage.py shell
>>> from django.contrib.auth import get_user_model
>>> User = get_user_model()
>>> u = User.objects.get(username='john')
>>> u.set_password('new password') # To hash!!
>>> u.save()
照合時には authenticate
を利用する。
from django.contrib.auth import authenticate, login, logout
user = authenticate(username='john', password='secret')
if user is not None:
login(request, user) # request セッションに認証情報をぶち込み
else:
logout(request) # ログアウトの例、本来こんな実装はしないケド
例によってセッションにユーザの Auth 認証セッションが入っている。Views / Templates で参照可能。
if request.user.is_authenticated:
# Do something for authenticated users.
...
else:
# Do something for anonymous users.
...
{% if user.is_authenticated %}
<a href="{% url 'account_logout' %}" class="uk-link-text">
<span uk-icon="user"></span> {% user_display user %}
</a>
{% endif %}
Views や Views のアクションについて django.contrib.auth の認証領域下にしたい場合、 views.py
でアクションを生やしているなら Decorator が、クラスベースのビューを利用しているなら Mixin が利用できる。
# views.py
from django.contrib.auth.decorators import login_required
@login_required
def my_view(request):
# ...
# views/my_view.py
from django.contrib.auth.mixins import LoginRequiredMixin
# LoginRequiredMixin は一番左でロードしてやる
class MyView(LoginRequiredMixin, View):
login_url = '/login/'
redirect_field_name = 'redirect_to'
User モデルオブジェクト自体は以下のように django.contrib.auth.models
から User モデルを参照可能ではある。但し、基本 User モデルはカスタム User モデルを配置することになるため、モデル定義時の ForeignKey なんかに突っ込むときは settings.AUTH_USER_MODEL
か get_user_model()
で参照する。
from django.contrib.auth import get_user_model
from django.db import models
class Article(models.Model):
author = models.ForeignKey(
get_user_model(),
on_delete=models.CASCADE,
)
title = models.CharField(max_length=100)
text = models.TextField()
モデルの管理アプリ。これを開発者ツールとするか、ユーザの管理画面とするかはアナタ次第。Django としては「adminサイトは、あなたのサイトのフロントエンドやその周辺を含んだ全体を作成することを意図していません」だが、例によってカスタマイズ用のフックが多数提供されている。
↑ 読めば大体雰囲気わかるかな。
Admin アプリにモデルを認識させる場合は、ModelAdmin クラスを生成し register で登録してやる。この ModelAdmin クラスをこねこねして Admin アプリ内でのふるまいを決めてやる。
models.py に一緒に書く記事が多いが、ModelAdmin オブジェクトは views 層のロジックが多くなりがちなので、別モジュールで切り出した方がいい。 ( models.py
は Django セットアップ初期でロードされる関係で、依存する import
は最上位モジュール・モデルだけに絞り view 関連の import
を排除する必要があるため )
# nyapp/models.py
from django.db import models
class User(models.Model):
# ...
class Article(models.Model):
# ...
# myapp/admins.py
from django.contrib import admin
from myapp.models import Article
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
#
# 存在する Attributes ( プロパティかメソッド ) を指定
# 関連モデル系の Attribute は文字列評価を受けるため
# __str__ でお名前を返却するようにしてやる
#
list_display = ['title', 'body']
list_editable = ['title'] # リストで編集可能にしてくれる
ordering = ['title']
search_fields = ['name'] # 検索 input を表示、ここのカラムが検索対象に
# myapp/admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from myapp.models import User
from myapp.admins import * # UserAdmin 以外で管理画面に表示する通常モデルをロード
# Django 管理画面 (django.contrib.admin) の
# 認証・管理で利用する UserAdmin を User モデルにセット
#
admin.site.register(User, UserAdmin)
from django.contrib import admin
from myapp.models import Article
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
actions = [make_published]
def make_published(self, request, queryset):
queryset.update(status='p')
make_published.short_description = 'Mark selected stories as published'
ModelAdmin クラスには change_form_template のような「編集画面のテンプレートファイルこれ使って」というフックプロパティや、response_change のような「POST リクエスト時のレスポンス変えて」というフックメソッドが用意されている。これらを利用して各モデルオブジェクトに対する「カスタム機能実行ボタン」を生やしたりできる。
# Model class.
class Villain(Entity):
...
is_unique = models.BooleanField(default=True)
# Template html.
{% extends 'admin/change_form.html' %}
{% block submit_buttons_bottom %}
{{ block.super }}
<div class="submit-row">
<input type="submit" value="Make Unique" name="_make-unique">
</div>
{% endblock %}
# Model Admin class.
@admin.register(Villain)
class VillainAdmin(admin.ModelAdmin, ExportCsvMixin):
...
change_form_template = "entities/villain_changeform.html"
def response_change(self, request, obj):
if "_make-unique" in request.POST:
matching_names_except_this = self.get_queryset(request).filter(name=obj.name).exclude(pk=obj.id)
matching_names_except_this.delete()
obj.is_unique = True
obj.save()
self.message_user(request, "This villain is now unique")
return HttpResponseRedirect(".")
return super().response_change(request, obj)
ModelAdmin.lookup_allowed(lookup, value)
Django管理画面 list_filterのカスタマイズ
https://django.readthedocs.io/en/stable/ref/contrib/admin/index.html#django.contrib.admin.ModelAdmin.lookup_allowed
https://django.readthedocs.io/en/stable/ref/contrib/admin/index.html#django.contrib.admin.ModelAdmin.list_filter
- モデルの一覧 (index) ページでは
?hoge_id=3
みたいなクエリでフィルタリングができる list_filter
プロパティのカスタムで表示制御できる- リレーションを使ったフィルタリングは、セキュリティの関係で
lookup_allowed
をいじって許可する必要ある
@admin.register(Comment)
class CommentAdmin(admin.ModelAdmin)
# lookup_allowed をオーバライドして
# Comment の index で ?article__user__id=3 みたいな
# フィルタリングを可能にするための変更
#
def lookup_allowed(self, lookup, value):
if lookup in ('article__user__id'):
return True
return super(lookup, value)
Django 2.0 x django-rest-framework でカンバンアプリ - codezine.jp - 実装の雰囲気
Django のおすすめライブラリ - 古め
Django 自体は WEB アプリフレームワークとしてリッチだが、Rails や新興の Laravel なんかと比べると本体の機能はそこまで多くなく最低限といったところ。このへんは Python のエコシステムに存在する Django 向けの Python パッケージを利用して拡張していくような使い方をしているみたい。
django-extensions/django-extensions - github.com - ユーティリティつめあわせ
$ pip install django-extensions
# settings.py
INSTALLED_APPS = [
# ...
'django_extensions',
]
# DB の ALL DROP
$ python manage.py db_reset
# ルーティング確認
$ python manage.py show_urls
CSV くれくれおじさん対策。django.contrib.admin に CSV のインポート/エクスポートを追加する。
高機能デバッガ、こういうの結局使わない
S3 とかとの連携
OAuth 対応のユーザ認証系ぜんぶやるライブラリ。django.contrib.auth および django.contrib.sites の拡張で提供される。テーブル/モデルに auth_user
を利用するが、通常作成したユーザは is_superuser
ぢゃないので /admin
ログインはできない。
また、メールによる認証を有効にした場合は「ユーザ登録」時にメール送信が挟まるので settings.py ならびに実行環境上でメール送信の設定をしてないとコケるの注意。
OAuth の設定はこのへんを参照 ... Providers / TwitterアカウントでのSNSログイン
$ pip install django-allauth
# settings.py
# django.contrib.sites で allauth サイトにするやつの ID
SITE_ID = 1
# この辺はルーティングや /profile 的なものを作るかどうか
LOGIN_URL = '/login/'
LOGIN_REDIRECT_URL = '/email/'
ACCOUNT_LOGOUT_REDIRECT_URL = '/'
# https ならこいつを変更、デフォルトは http
ACCOUNT_DEFAULT_HTTP_PROTOCOL = 'https'
# この辺はお好み
# ACCOUNT_USER_MODEL_USERNAME_FIELD = None
# ACCOUNT_EMAIL_REQUIRED = True
# ACCOUNT_USERNAME_REQUIRED = False
# ACCOUNT_AUTHENTICATION_METHOD = 'email'
INSTALLAED_APPS = (
# The following apps are required:
'django.contrib.auth',
'django.contrib.messages',
'django.contrib.sites',
'allauth',
'allauth.account',
'allauth.socialaccount',
# ... include the providers you want to enable:
# 'allauth.socialaccount.providers.twitter',
)
TEMPLATES = [
# ...
'DIRS': [
# テンプレートのオーバライド用
#
# @see https://github.com/pennersr/django-allauth/tree/master/allauth/templates
#
# 上記を参考にオーバライドしたいやつだけディレクトリ / html を作成
# extends でレイアウト変更したいだけなら base.html だけ変えれば OK
# 作成してないディレクトリは以下で指定しないこと
#
# os.path.join(BASE_DIR, 'your-project', 'templates'),
# os.path.join(BASE_DIR, 'your-project', 'templates', 'allauth'),
# os.path.join(BASE_DIR, 'your-project', 'templates', 'allauth', 'account'),
# os.path.join(BASE_DIR, 'your-project', 'templates', 'allauth', 'socialaccount'),
],
'OPTIONS': [
'context_processors': [
# ...
'django.template.context_processors.request',
]
]
]
AUTH_USER_MODEL = 'myapp.User' # カスタム User クラス指定
AUTHENTICATION_BACKENDS = (
# ...
# AUTH バックエンドを allauth 固有仕様 ( e-mail 強制 ) に寄せる
'allauth.account.auth_backends.AuthenticationBackend',
# 従来の username 方式を採用する場合は以下
# 'django.contrib.auth.backends.ModelBackend',
)
# urls.py
urlpatterns = [
# ルーティングやデフォルトテンプレートの利用については
# 案件によってカスタマイズすればよろし
#
path('', include('allauth.urls')),
path('', lambda r: HttpResponseRedirect('login')),
]
$ python manage.py migrate
ここまでやったら /admin/sites
から SITE_ID
で指定した django.contrib.sites サイトを選択して、ドメインを設定。ドメインを 192.168.99.100
にした場合、ルーティング /ドメイン/accounts/signup
でユーザ登録へ行ける。全ルーティングは django-extensions の show_urls でもみて。
また、E メール確認をしてからユーザを承認 ... みたいな細かなふるまいは settings.py で Configuration を参照しながら設定する感じ。
django.contrib.auth 拡張なので、Django 公式の認証系トピックをあされば大体の操作は可能。その他 allauth 特有のユーザインスタンス操作 API や、メール文など実際のプロダクトでのカスタマイズはマニュアルを参照。
- Signals
- 各種認証系イベントにたいしてコールバックをフック可能
- Templates
- Forms
- Advanced Usage
テンプレートタグはこんな感じ。
{% load account %}
{% user_display user as user_display %}
{% blocktrans %}{{ user_display }} has logged in...{% endblocktrans %}
{% load socialaccount %}
{% providers_media_js %}
{% get_social_accounts user as accounts %}
{{accounts.twitter}} -- a list of connected Twitter accounts
{{accounts.twitter.0}} -- the first Twitter account
{% if accounts %} -- if there is at least one social account
{% get_providers as socialaccount_providers %}
<a href="{% provider_login_url "openid" openid="https://www.google.com/accounts/o8/id" next="/success/url/" %}">Google</a>
<a href="{% provider_login_url "twitter" %}">Twitter</a>
また django.contrib.auth.admin に対して django-allauth の認証を前段にかましてやる場合は以下。
# admin.py
from django.contrib import admin
from django.contrib.auth.decorators import login_required
admin.site.login = login_required(admin.site.login)
django-rest-framework.org encode/django-rest-framework - github.com
Django REST Frameworkを使って爆速でAPIを実装する
Django での REST Web API 実装フレームワーク。