93
スゴイ Django based on Django 1.11 and Python 3.6.n makoto tsuyuki - UNCOVER TRUTH Inc. Python&Django で始める Web 開発 in 札幌 #1 2017.11.11

スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Embed Size (px)

Citation preview

Page 1: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

スゴイ Django based on Django 1.11 and Python 3.6.n

makoto tsuyuki - UNCOVER TRUTH Inc.

Python&Djangoで始めるWeb開発 in 札幌 #1 2017.11.11

Page 2: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

お前、誰よ

tsuyukimakoto a.k.a everes

鎌倉から来ました

django-ja 初代ドメインホルダー

最初に買ったPythonの本

「Pythonテクニカルリファレンス」

株式会社UNCOVER TRUTHで働いてます。エンジニア探してます

https://www.uncovertruth.co.jp/ja/userdive/

Page 3: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

djangoとの関わり

2005年7月から触ってます

2006年2月に4人でdjango-jaを始めました

2009年頃までDjango勉強会を開催してた

Page 4: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

djangoとは?

Page 5: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Django Reinhardt

Page 6: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Web Application

Framework

Page 7: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Vs Ruby on Rails

Page 8: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Django beats …

Do you know Zope?

Page 9: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Django before 1.0

そもそもは2003年から

Page 10: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Django before 1.0

Django to be The Python Web Framework

by Guido van Rossum @SciPy2006

Page 11: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Full Stack

MVC vs MTV

Page 12: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Full Stack

MVC vs MTV

Model = Model

Page 13: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Full Stack

MVC vs MTV

View ≠ Template

Page 14: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Full Stack

MVC vs MTV

Controller ≠ View

Page 15: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Full Stack

Page 16: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Stable

ドキュメンテーションされたAPIが無くなる時は特定のプロセスを経て消される

7年前のSoozyConのスライドを見返していたけれど、当時と設計思想は変わっていない

Page 17: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Secure

NASA

Mozilla

https://docs.djangoproject.com/en/dev/internals/security/#reporting-security

Page 18: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

admin

RoRのScaffoldに対して、djangoにはadminがある

Page 19: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

https://youtu.be/pkETpPayyFc

Page 20: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Fundamentals

Page 21: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

設計思想

ルースカップリング

コード量の低減

迅速な開発

DRY (Don’t repeat yourself) 則

暗示的より明示的に

一貫性

https://docs.djangoproject.com/en/1.11/misc/design-philosophies/

Page 22: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

API stability• ドキュメンテーションされたAPがstable

• remain in the API for

at least two feature

releases.

https://docs.djangoproject.com/en/1.11/misc/api-stability/

Page 23: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

HTTP

Requestを受けて

処理をして

Responseを返す

Page 24: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

WSGI

Python Web Server Gateway Interface

PEP333, 3333

引数を2つ受け取るCallableを返す

1つ目はRequestに関する情報

2つ目はCallback

django.core.handlers.WSGIHandler あたりから追っていくと全体が見えます

Page 25: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Request to Response

Page 26: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

djangoのMiddleware

__call__ (Viewの実行前)

URLconfを使ってHandlerがURLに対応するViewを探す

process_view

Viewが実行される(Responseが生成される)

process_template_response

__call__ (Viewの実行後)

process_exception

>>> class A:

... def __call__(self):

... print('called!')

...

>>> a = A()

>>> a()

called!

>>> def outer():

... def inner():

... print('hello world')

... return inner

...

>>> o = outer()

>>> o()

hello world

Page 27: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

デフォルトのMiddlewareMIDDLEWARE = [

'django.middleware.security.SecurityMiddleware',

'django.contrib.sessions.middleware.SessionMiddleware',

'django.middleware.common.CommonMiddleware',

'django.middleware.csrf.CsrfViewMiddleware',

'django.contrib.auth.middleware.AuthenticationMiddleware',

'django.contrib.messages.middleware.MessageMiddleware',

'django.middleware.clickjacking.XFrameOptionsMiddleware',

]

Request

ResponseView

Page 28: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

blog/middlewares.py

Page 29: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

hokkaido/settings.py

Page 30: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

呼び出すとfirst middlewqre before view

second middlewqre before view

django.core.handlers.BaseHandler._get_response: resolver.resolve

first middlewqre process_view

second middlewqre process_view

IndexView: get

second middlewqre process_template_response

first middlewqre process_template_response

second middlewqre after view

first middlewqre after view

Page 31: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Model

Modelに全部書く勢い

DBのテーブル作成に必要な情報も

入力チェックに必要な情報も

関連も書く

ビジネスロジック的なものも書く

Page 32: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

blogアプリケーションのEntryモデル

Page 33: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

ModelForm

>>> from blog.models import Entry

>>> from django.forms import ModelForm

>>> class EntryForm(ModelForm):

... class Meta:

... model = Entry

... excludes = ['created']

>>>

>>> form = EntryForm(dict(slug='test3', title='MF'))

>>> form.is_valid()

False

>>> form.errors

{'released': ['This field is required.'], 'author': ['This field is

required.’]}

Page 34: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

ModelForm

>>> entry = Entry.objects.get(pk=1)

>>> form = EntryForm(instance=entry)

>>> form.as_ul()'<li><label for="id_slug">Slug:</label> <input type="text" name="slug" value="test"

maxlength="50" required id="id_slug" /> <span class="helptext">Part of the URL describing the

content</span></li>\n<li><label for="id_title">Title:</label> <input type="text" name="title"

value="北海道へ来ました!" maxlength="128" required id="id_title" /></li>\n<li><label

for="id_released">Release date / time:</label> <input type="text" name="released"

value="2017-11-05 17:55:34" required id="id_released" /><input type="hidden" name="initial-

released" value="2017-11-05 17:55:34" id="initial-id_released" /></li>\n<li><label

for="id_author">Author:</label> <select name="author" required id="id_author">\n <option

value="">---------</option>\n\n <option value="1" selected>makoto</option>\n\n</select></li>'

Page 35: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

manage.py shellで遊ぶ

$ python manage.py shell

>>> from blog.models import Entry

>>> from django.contrib.auth import get_user_model

>>> me =

get_user_model().objects.filter(email='[email protected]')[

0]

>>> me

<User: makoto>

Page 36: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

manage.py shellで遊ぶ

>>> entry = Entry(slug='test', title='北海道へ来ました!',

author=me)

>>> entry.save()

/Users/makoto/venv/hokkaido/lib/python3.6/site-

packages/django/db/models/fields/__init__.py:1451:

RuntimeWarning: DateTimeField Entry.released

received a naive datetime (2017-11-05

17:55:34.238327) while time zone support is active.

RuntimeWarning)

Page 37: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

manage.py shellで遊ぶ

>>> for entry in Entry.objects.all():

... print(f'{entry.pk} {entry.slug}: {entry.title} by

{entry.author.username}')

...

1 test: 北海道へ来ました! by makoto

Page 38: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

manage.py shellで遊ぶ

>>> me.entry_set.all()[0].title

'北海道へ来ました!'

me は django.contrib.auth.models.User

Page 39: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

manage.py shellで遊ぶ

>>> me.entry_set.create(slug='test2', title=‘meのEntry

を追加')

<Entry: Entry object>

>>> _.author

<User: makoto>

Page 40: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Queryset

Entry.objects.all()は条件が格納されたQuerysetのインスタンスを返します

🤔

Page 41: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

QuerysetLOGGING = {

'version': 1,'handlers': {

'console': {'level': 'DEBUG','class': 'logging.StreamHandler',

},},'loggers': {

'django.db.backends': {'handlers': ['console'],'level': 'DEBUG',

},},

}

Page 42: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Queryset

>>> from blog.models import Entry

>>> qs = Entry.objects.all()

>>> list(qs)

(0.001) SELECT "blog_entry"."id", "blog_entry"."slug",

"blog_entry"."title", "blog_entry"."released",

"blog_entry"."created", "blog_entry"."author_id" FROM

"blog_entry"; args=()

[<Entry: Entry object>, <Entry: Entry object>]

Page 43: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Queryset - filter

>>> qs1 = qs.filter(slug='test')

>>> list(qs)

[<Entry: Entry object>, <Entry: Entry object>]

>>> list(qs1)

(0.000) SELECT "blog_entry"."id", "blog_entry"."slug",

"blog_entry"."title", "blog_entry"."released",

"blog_entry"."created", "blog_entry"."author_id" FROM

"blog_entry" WHERE "blog_entry"."slug" = 'test'; args=('test',)

[<Entry: Entry object>]

Page 44: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Queryset - exclude>>> qs2 = qs.exclude(slug='test')

>>> list(qs2)

(0.000) SELECT "blog_entry"."id", "blog_entry"."slug",

"blog_entry"."title", "blog_entry"."released",

"blog_entry"."created", "blog_entry"."author_id" FROM

"blog_entry" WHERE NOT ("blog_entry"."slug" = 'test');

args=('test',)

[<Entry: Entry object>]

Page 45: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Queryset -関連>>> Entry.objects.filter(author__email='[email protected]')

(0.000) SELECT "blog_entry"."id", "blog_entry"."slug",

"blog_entry"."title", "blog_entry"."released",

"blog_entry"."created", "blog_entry"."author_id" FROM

"blog_entry" INNER JOIN "auth_user" ON

("blog_entry"."author_id" = "auth_user"."id") WHERE

"auth_user"."email" = '[email protected]' LIMIT 21;

args=('[email protected]',)

<QuerySet [<Entry: Entry object>, <Entry: Entry object>]>

Page 46: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Queryset - exact>>> qs.exclude(slug__exact='test')

(0.000) SELECT "blog_entry"."id", "blog_entry"."slug",

"blog_entry"."title", "blog_entry"."released",

"blog_entry"."created", "blog_entry"."author_id" FROM

"blog_entry" WHERE NOT ("blog_entry"."slug" = 'test') LIMIT 21;

args=('test',)

<QuerySet [<Entry: Entry object>]>

Page 47: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Queryset - Q>>> from django.db.models import Q

>>> Entry.objects.filter(Q(slug='test')|Q(slug='test2'))

(0.001) SELECT "blog_entry"."id", "blog_entry"."slug", "blog_entry"."title",

"blog_entry"."released", "blog_entry"."created", "blog_entry"."author_id" FROM

"blog_entry" WHERE ("blog_entry"."slug" = 'test' OR "blog_entry"."slug" = 'test2')

LIMIT 21; args=('test', ‘test2')

<QuerySet [<Entry: Entry object>, <Entry: Entry object>]>

>>> Entry.objects.filter(Q(slug__contains='t')&Q(slug__contains='2'))

(0.000) SELECT "blog_entry"."id", "blog_entry"."slug", "blog_entry"."title",

"blog_entry"."released", "blog_entry"."created", "blog_entry"."author_id" FROM

"blog_entry" WHERE ("blog_entry"."slug" LIKE '%t%' ESCAPE '\' AND

"blog_entry"."slug" LIKE '%2%' ESCAPE '\') LIMIT 21; args=('%t%', '%2%')

<QuerySet [<Entry: Entry object>]>

Q(slug='test')|Q(slug='test2')

Q(slug__contains='t')&Q(slug__contains='2')

Page 48: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Queryset - and>>> Entry.objects.filter(

slug='test', author__email__contains='gmail'

).exclude(

author__email__startswith='spam'

)

(0.000) SELECT "blog_entry"."id", "blog_entry"."slug",

"blog_entry"."title", "blog_entry"."released", "blog_entry"."created",

"blog_entry"."author_id" FROM "blog_entry" INNER JOIN

"auth_user" ON ("blog_entry"."author_id" = "auth_user"."id")

WHERE ("blog_entry"."slug" = 'test' AND "auth_user"."email" LIKE

'%gmail%' ESCAPE '\' AND NOT ("auth_user"."email" LIKE

'spam%' ESCAPE '\')) LIMIT 21; args=('test', '%gmail%', 'spam%')

<QuerySet [<Entry: Entry object>]>

Page 49: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Queryset - slice>>> Entry.objects.all()[1]

>>> Entry.objects.all()[:1]

>>> Entry.objects.all()[1:2]

>>> Entry.objects.all()[::2]

Page 50: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Queryset - others…annotate, order_by, reverse, distinct, values, values_list, dates,

datetimes, none, union, intersection, difference, select_related,

prefetch_related, extra, defer, only, using, select_for_update,

raw, Methods that do not return QuerySets, get, create,

get_or_create, update_or_create, bulk_create, count, in_bulk,

iterator, With server-side cursors, Without server-side cursors,

latest, earliest, first, last, aggregate, exists, update, delete,

as_manager, Field lookups, exact, iexact, contains, icontains, in,

gt, gte, lt, lte, startswith, istartswith, endswith, iendswith, range,

date, year, month, day, week, week_day, time, hour, minute,

second, isnull, search, regex, iregex, Aggregation functions,

expression, output_field, **extra, Avg, Count, Max, Min, StdDev,

Sum, Variance

https://docs.djangoproject.com/en/1.11/ref/models/querysets/

Page 51: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Inheritance - abstract

from django.db import models

class CommonInfo(models.Model):

name = models.CharField(max_length=100)

age = models.PositiveIntegerField()

class Meta:

abstract = True

class Student(CommonInfo):

home_group = models.CharField(max_length=5)

https://docs.djangoproject.com/en/1.11/topics/db/models/#abstract-base-classes

Id

name

age

home_group

Page 52: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Inheritance - separateclass Place(models.Model):

name = models.CharField(max_length=50)

address = models.CharField(max_length=80)

class Restaurant(Place):

serves_hot_dogs =

models.BooleanField(default=False)

serves_pizza = models.BooleanField(default=False)

https://docs.djangoproject.com/en/1.11/topics/db/models/#multi-table-inheritance

id

name

address

place_ptr_id

serves_hot_dogs

serves_pizza

1to1

Page 53: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

MultiDB -

DATABASE_ROUTERSclass AuthRouter(object):

def db_for_read(self, model, **hints):

if model._meta.app_label == 'auth':

return 'auth_db'

return None

def db_for_write(self, model, **hints):

return None

def allow_relation(self, obj1, obj2, **hints):

return None

def allow_migrate(self, db, app_label, model_name=None, **hints):

return None

https://docs.djangoproject.com/en/1.11/topics/db/multi-db/#using-routers

Page 54: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Template

継承

プレゼンテーションとロジックの分離

冗長さを防ぐ

XML をテンプレート言語に使わない

プログラミング言語を作り直さない

Page 55: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Template - variables

{{ variable }}

Page 56: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Template - loop

{% for variable in some_list %}

{% empty %}

{% endfor %}

• forloop.counter

• forloop.counter0

• forloop.first

• forloop.last

• etc…

Page 57: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Template - if

{% if variable %}

{% elif variable2 > 0 %}

{% else %}

{% endif %}

Page 58: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Template - tag

{% for o in some_list %}

<tr class="{% cycle 'row1' 'row2' %}">

...

</tr>

{% endfor %}

https://docs.djangoproject.com/en/1.11/ref/templates/builtins/

Page 59: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Template - filter

{{ value|linebreaksbr }}

https://docs.djangoproject.com/en/1.11/ref/templates/builtins/

Page 60: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Template - inheritance<html>

<head>{% block title %}プロジェクト名:{% endblock title %}</head>

<script type="text/javascript" src="common.js"></script>

{% block custom_js %}{% endblock custom_js %}

<body>

<div id="menu">{% block menu %}{% endblock menu %}</div>

<div id="content">{% block content %}{% endblock content %}</div>

<div id=”copyright”>{% block copyright %}everes{% endblock %}</div>

</body>

</html>

{% extends 'base.html% %}

{% block title %}{{ block.super }}アプリ名とか{% endblock title %}

{% block menu %}アプリレベルのメニューとか{% endblock menu %}

{% extends 'app/base.html' %}

{% block content %}内容内容内容無いよう{% endblock content %}

<head>{% block title %}プロジェクト名:{% endblock title %}</head>

{% block title %}{{ block.super }}アプリ名とか{% endblock title %}

{% block content %}内容内容内容無いよう{% endblock content %}

<head>{% block title %}プロジェクト名:{% endblock title %}</head>

<div id="content">{% block content %}{% endblock content %}</div>

base.html

app/base.html

app/some.html

Page 61: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

View

簡潔性

リクエストオブジェクトの利用

ルースカップリング

GET と POST の使い分け

Page 62: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

URLconf

from django.conf.urls import url

from . import views

urlpatterns = [

url(r'^articles/2003/$', views.special_case_2003),

url(r'^articles/([0-9]{4})/$', views.year_archive),

url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),

url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$',

views.article_detail),

]

https://docs.djangoproject.com/en/1.11/topics/http/urls/

Page 63: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

URLconf

from django.conf.urls import url

from . import views

urlpatterns = [

url(r'^articles/2003/$', views.special_case_2003),

url(r'^articles/([0-9]{4})/$', views.year_archive),

url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),

url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$',

views.article_detail),

]

https://docs.djangoproject.com/en/1.11/topics/http/urls/

views.month_archive(request, ‘2017’, ’11’)

/articles/2017/11/

Page 64: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

URLconf

from django.conf.urls import url

from . import views

urlpatterns = [

url(r'^articles/2003/$', views.special_case_2003),

url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),

url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$',

views.month_archive),

url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-

9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),

]

https://docs.djangoproject.com/en/1.11/topics/http/urls/

views.month_archive(request, year=‘2017’, month=’11’)

/articles/2017/11/

Page 65: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

View - function based

import datetime

from django.http import HttpResponse

def current_datetime(request):

now = datetime.datetime.now()

html = "<html><body>It is now %s.</body></html>" % now

return HttpResponse(html)

https://docs.djangoproject.com/en/1.11/topics/http/views/

Page 66: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

View - class based

from django.views.generic.base import View

from django.http import HttpResponse

class IndexView(View):

def dispatch(self, request, year=None, month=None):

html = f'<html><body>{year}/{month}</body></html>'

return HttpResponse(html)

https://docs.djangoproject.com/en/1.11/topics/http/views/

Page 67: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

View - class based

from django.views.generic.base import View

from django.http import HttpResponse

class IndexView(View):

def dispatch(self, request, year=None, month=None):

html = f'<html><body>{year}/{month}</body></html>'

return HttpResponse(html)

https://docs.djangoproject.com/en/1.11/topics/http/views/

url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', IndexView.as_view()),

Page 68: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

View - class based

get

post

put

patch

https://docs.djangoproject.com/en/1.11/ref/class-based-views/base/#view

delete

head

options

trace

Page 69: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

View - idiomfrom django.http import HttpResponseRedirect

from django.shortcuts import render

from .forms import MyForm

def myview(request):

if request.method == "POST":

form = MyForm(request.POST)

if form.is_valid():

# <process form cleaned data>

return HttpResponseRedirect('/success/')

else:

form = MyForm(initial={'key': 'value'})

return render(request, 'form_template.html', {'form': form})

https://docs.djangoproject.com/en/1.11/topics/class-based-views/intro/#handling-forms-with-class-based-views

Page 70: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

View - idiom

class MyFormView(View):

form_class = MyForm

initial = {'key': 'value'}

template_name = 'form_template.html'

def get(self, request, *args, **kwargs):

form = self.form_class(initial=self.initial)

return render(request, self.template_name, {'form': form})

def post(self, request, *args, **kwargs):

form = self.form_class(request.POST)

if form.is_valid():

# <process form cleaned data>

return HttpResponseRedirect('/success/')

return render(request, self.template_name, {'form': form})

https://docs.djangoproject.com/en/1.11/topics/class-based-views/intro/#handling-forms-with-class-based-views

Page 71: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Generic View

Page 72: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

TemplateView

from django.views.generic import TemplateView

class AboutView(TemplateView):

template_name = "about.html"

url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', TemplateView.as_view(template_name=‘about.html’)),

Page 73: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Generic display views

DetailView

ListView

from django.views.generic.list import ListView

from articles.models import Article

class ArticleListView(ListView):

model = Article

https://docs.djangoproject.com/en/1.11/ref/class-based-views/generic-display/

Page 74: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Generic editing views

FormView / CreateView / UpdateView / DeleteView

https://docs.djangoproject.com/en/1.11/ref/class-based-views/generic-editing/

from django.views.generic.edit import CreateView

from myapp.models import Author

class AuthorCreate(CreateView):

model = Author

fields = ['name']

Page 75: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Signal

アプリケーション間で連携しつつルースカップリングに保つ

https://docs.djangoproject.com/en/1.11/topics/signals/

Page 76: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Signalをreceiveする

from django.db.models.signals import post_save

from django.dispatch import receiver

from myapp.models import MyModel

@receiver(post_save, sender=MyModel)

def my_handler(sender, **kwargs):

...

https://docs.djangoproject.com/en/1.11/topics/signals/#connecting-to-signals-sent-by-specific-senders

Page 77: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Signalを独自定義する

import django.dispatch

pizza_done = django.dispatch.Signal(

providing_args=["toppings", “size"]

)

https://docs.djangoproject.com/en/1.11/topics/signals/#defining-and-sending-signals

Page 78: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Signalを独自定義する

https://docs.djangoproject.com/en/1.11/topics/signals/#defining-and-sending-signals

class PizzaStore(object):

def send_pizza(self, toppings, size):

pizza_done.send(sender=self.__class__,

toppings=toppings, size=size)

...

Page 79: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

–本丸にたどり着いた

“ReUsable Application”

Page 80: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

ProjectとApplication

Page 81: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Project

settings.py

urls.py

from django.conf.urls import include, url

urlpatterns = [

url(r'^community/', include(‘app_a.urls')),

url(r'^contact/', include(‘app_b.urls’)),

]

Page 82: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Application

models.py

views.py

admin.py

apps.py

urls.py

templates (フォルダ)

Page 83: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Application - templates

models.py

views.py

admin.py

apps.py

urls.py

templates (フォルダ)

Page 84: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Application - urls.py

app_name = ‘blog'

urlpatterns = [

url(r'^articles/2003/$', views.special_case_2003,

name=‘special_case_2003’),

url(r'^articles/([0-9]{4})/$', views.year_archive,

name=‘year_archive’),

]

{% url ‘blog:year_archive' 2003 %}

Page 85: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

Application - auth

from django.contrib.auth impor get_user_model

UserModel = get_user_model()

Page 86: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

django.conf.global_settings

DEFAULT_FILE_STORAGE

FILE_UPLOAD_HANDLERS

MIDDLEWARE_CLASSES

SESSION_ENGINE

CACHES

AUTHENTICATION_BACKENDS

DEFAULT_EXCEPTION_REPORTER_FILTER

TEST_RUNNER

STATICFILES_STORAGE

STATICFILES_FINDERS

Page 87: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

to see next

Page 88: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

https://docs.djangoproject.com/

Page 89: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

https://github.com/django/django/

Page 90: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

https://sentry.io/https://github.com/getsentry/sentry

Page 91: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

http://pinaxproject.com

Page 92: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

https://djangopackages.or

g

2880

Page 93: スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1

http://amzn.to/2hQU2Be

Two scoops djangoでググれば出てきますけどね

Any Question?