巳年じゃないけど Python やろうぜ(その 10)
だいぶシリーズが長期化してきました(苦笑)
Model で遊ぶ
今回使用するデータは「現場で使えるSQL 第2版」のものを使用することにします。
現場で使えるSQL 第2版 (DB Magazine SELECTION)
- 作者: 小野哲,藤本亮
- 出版社/メーカー: 翔泳社
- 発売日: 2006/11/16
- メディア: 単行本(ソフトカバー)
- 購入: 2人 クリック: 22回
- この商品を含むブログ (12件) を見る
$ ./manage.py shell Python 3.6.0 (default, Feb 4 2017, 00:11:30) [GCC 6.3.1 20161221 (Red Hat 6.3.1-1)] on linux Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>> from customer_search.models import Customer >>> Customer.objects.all() <QuerySet []> >>> c = Customer(name='(株)ワイキキソフト', phone='090-AAAA-AAAA') >>> c.save() >>> c.id 1 >>> c.name '(株)ワイキキソフト' >>> c.phone '090-AAAA-AAAA' >>> Customer.objects.all() <QuerySet [<Customer: Customer object>]>
save
はテーブルにデータを保存するメソッドです。実際に DB Browser for SQLite で確認した画面がこちら。
確かにデータは保存されています…が、チュートリアルでは objects.all()
の出力を見て「これは困りました*1ね」というお話になります。これはオブジェクトを表示するときに文字列化する models.Model.__str__
メソッドをオーバーライドしていないので、デフォルトのものが使用されている*2ことによります。
このままだと、後程説明する管理画面での表示にも差し障るので、models.py
を改造しましょう。
from django.db import models # Create your models here. class Customer(models.Model): name = models.CharField(max_length=20) phone = models.CharField(max_length=20) def __str__(self): return self.name
自身の name
の内容を表示するように変更しました。もう一度 shell を起動して確認してみましょう。
$ ./manage.py shell Python 3.6.0 (default, Feb 4 2017, 00:11:30) [GCC 6.3.1 20161221 (Red Hat 6.3.1-1)] on linux Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>> from customer_search.models import Customer >>> Customer.objects.all() <QuerySet [<Customer: (株)ワイキキソフト>]> >>> Customer.objects.filter(id=1) <QuerySet [<Customer: (株)ワイキキソフト>]> >>> Customer.objects.get(pk=1) <Customer: (株)ワイキキソフト>
filter
は条件に合致するデータを全て取得するもので、出力の型は QuerySet
になっています。一方の get
は主キーを指定してそれに該当する単一のデータを取得するものなので、出力の型は Customer
になります。
表示に顧客名が表示されていて、いい感じですね。次回は管理画面を利用して Model を管理する方法について書きます。
巳年じゃないけど Python やろうぜ(その 9)
Model を扱う
いよいよ今回から Model を扱います。
…の前に。
新しいアプリの作成
端末からコマンドを入力して新しいアプリを作成します。
$ ./manage.py startapp customer_search
今回はデータベース内のレコードを ID を入力して顧客を検索する customer_search アプリを作ります。なお今回から Linux 上で作業していますが、基本となる手順はほぼ同じ*1です。
settings.py
の編集を忘れずに。
# Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'hello', 'customer_search', # 追加 ]
Model を作成する
Model の作成は、Model に対応する class を models.py
に書くだけです。と言っても、Rails みたいにコマンド一つで自動生成、とは行かないのが難点ですが…。
from django.db import models # Create your models here. class Customer(models.Model): name = models.CharField(max_length=20) phone = models.CharField(max_length=20)
今回は Customer (顧客)という単一のモデルを扱うことにします。モデル同士の関連性についてはまた後程ということで。
CharField
は VARCHAR
型に対応するもので、max_length
にバイト数を指定できます。このコードは SQL の VARCHAR(20)
という型宣言と同等になります。なお、主キーは特に指定しなければデフォルトで id
というフィールドが勝手に作成されます。
Model を有効にする
作った Model を有効にするための作業が必要です。まずは
$ ./manage.py makemigrations customer_search Migrations for 'customer_search': search/migrations/0001_initial.py: - Create model Customer
sqlmigrate
コマンドを使うと、migrate
コマンドを実行した時に実際に発行される SQL が読めます*2。
$ ./manage.py sqlmigrate search 0001 BEGIN; -- -- Create model Customer -- CREATE TABLE "customer_search_customer" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(20) NOT NULL, "phone" varchar(20) NOT NULL ); COMMIT;
customer_search_customer
という新たなテーブルが作成されるようですね。では migrate
を実行しましょう。
$ ./manage.py migrate Operations to perform: Apply all migrations: admin, auth, contenttypes, customer_search, sessions Running migrations: Applying customer_search.0001_initial... OK
システムに必要なテーブルは既に作成されているので、今回は新しく追加したものだけが実行されました。
巳年じゃないけど Python やろうぜ(その 8)
3 週間ほど空いてしまいました。この間こっそりと開発環境を Linux に移行させていたのは秘密です*1。
hello ページを作る(続き)
静的ファイル(CSS, JavaScript, etc...)の配置
今回は CSS を配置してみます。django_test\hello\static\hello
というフォルダを作り、その中に css\hello.css
を作成します。
body { background-color: #f8f8f8; color: #0c3c26; } p { font-size: large; } label { font-weight: bold; }
次に common.html
を書き換えます。
{% load static %} <!doctype html> <html> <head> <title>{{ page_title | title }}</title> <link rel="stylesheet" href="{% static 'hello/css/hello.css' %}"> </head> <body> {% block content %}{% endblock %} </body> </html>
サーバーを起動して確認してみましょう。
わかりにくいですが、文字色と背景色を Django の公式ドキュメントに合わせています。
JavaScript や画像ファイルなど、その他の静的ファイルも同様の方法で配置して読み込むことができます。
…君らそろそろ Model 使いたいやろ ? というわけで、次回からいよいよ Model です !
巳年じゃないけど Python やろうぜ(その 6)
Hello ページを作る(続き)
前回までで、テンプレートを利用して Web ページを表示させることができましたが、まだ Web アプリっぽくないですよね。
もう少しそれっぽくするにはフォームとかあったらいいんじゃないでしょうかね。
フォームを作成する
今回はフォームを使って
http://localhost:8000/hello/
にアクセスしたら、名前を入力するフォームが表示されるようにする- 名前を入力して送信したら、それを表示専用のページに渡して表示させる。リダイレクト先は
http://localhost:8000/hello/thanks/
とする(「名前を入力してくれてありがとう !」的な感じ)
巳年じゃないけど Python やろうぜ(その 5)
前回からの続きです。
Hello ページを作る(続き)
HttpResponse
に HTML を渡すための方法として、テンプレートを用いることにします。
まず django_test\hello
の下に templates
というフォルダを作り、さらにその中に hello
というフォルダを作ります(このようにするわけは後で説明します。)
django_test\hello\templates\hello\hello.html
を以下の内容で作成します。
<!doctype html> <html> <head> <title>Hello Page</title> </head> <body> <p>Hello, Django!</p> </body> </html>
django_test\hello\views.py
を以下のように修正します。
from django.template import loader # 追加 from django.http import HttpResponse def index(request): template = loader.get_template('hello/hello.html') html = template.render() return HttpResponse(html)
サーバを起動して確認してみましょう。
テンプレートの置き場所として、templates
フォルダの中にもう一度 hello
フォルダを作りましたが、これには理由があります。Django では、仮に
django_test\foo\templates\index.html
django_test\bar\templates\index.html
と、異なるアプリで同名のテンプレートがあったとき、常に 先に検出した テンプレートを読み込んでしまいます。そのため、意図しないテンプレートを読み込んでしまわないように「名前空間」を付けて
django_test\foo\templates\foo\index.html
django_test\bar\templates\bar\index.html
のように管理するわけです。
ビューで使える便利なショートカット
テンプレートを読み込んで、それをレンダリングして HttpResponse
に渡す、といった処理は頻繁に行います。そのため django.shortcuts
に render
という関数が用意されています。
from django.shortcuts import render def index(request): return render(request, 'hello/hello.html')
この 1 行目は、最初に hello
アプリを作った直後の views.py
のものと同じです。それだけよく使う、ということで、最初から用意してくれているんですね。ちなみに render_to_response
というのもありますが、公式ドキュメントによると非推奨、かつ将来的に廃止予定になるようです。
テンプレートに変数を埋め込む
実際にはどっか(データベースとか)から取得してきたデータをテンプレートに渡して値を埋め込むような処理をすることが多いでしょう。公式ドキュメントを見ると、render
の第三引数に辞書を渡すことでそれができることが分かります。
from django.shortcuts import render def index(request): my_name = 'Django' return render(request, 'hello/hello.html', {'my_name': my_name})
<!doctype html>
<html>
<head>
<title>Hello Page</title>
</head>
<body>
<p>Hello, {{ my_name }}!</p>
</body>
</html>
テンプレートの方に独特の記法が出てきました。これが Django のテンプレートならではの記法です。今後いろいろなところで出てきます。ちなみに拡張子は html
のままで大丈夫です。
巳年じゃないけど Python やろうぜ(その 4)
ちょっと前回の補足。
もし Python 3.6.0 しか入れていないか、もしくは Python 2.7.x の後に Python 3.6.0 をインストールしていて、なおかつ Python Launcher をインストールしていたなら、開発用サーバの起動は
>manage.py runserver
で行えます。その他の Django 用のコマンドも同様に実行できます。
Django アプリを作る
アプリを作るためのコマンドは「うまくいった!」のページに書いてありましたね。今回は hello
という名前のアプリを作ります。
>manage.py startapp hello
こんな感じで新たに hello
というフォルダができています。
django_test │ db.sqlite3 │ manage.py │ ├─django_test │ settings.py │ urls.py │ wsgi.py │ __init__.py │ └─hello │ admin.py │ apps.py │ models.py │ tests.py │ views.py │ __init__.py │ └─migrations __init__.py
Hello ページを作る
実際に Hello ページを作ってみましょう。django_test\hello\views.py
を編集して以下のようにします。
from django.http import HttpResponse def index(request): return HttpResponse('Hello, Django!')
Python のお作法として
- 関数定義などのブロックはインデント(半角スペース 4 個)で明示する
- 関数定義やクラス定義などの前には空行を二つ入れる
- ファイルの終端は改行で終わる
などがあります。だいたいは pep8 が教えてくれるので、その通りにやりましょう。
次に django_test\django_test\urls.py
を編集します。
from django.conf.urls import url, include # include を追加 from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^hello/', include('hello.urls')), # この行を追加 ]
コメントは分かりやすさのために入れてるので、実際には書かなくても大丈夫*1です。
これは何をやっているのかというと、http://localhost:8000/hello/
にアクセスしたら、それ以降の URL 文字列の処理を hello
アプリの urls
モジュールに委ねますよ、ということです。
なので、当然 django_test\hello\urls.py
を作成することになります。このファイルはあらかじめ用意されていないので、新規に作成します。
from django.conf.urls import url from . import views urlpatterns = [ url(r'^$', views.index), ]
これで http://localhost:8000/hello/
にアクセスしたら、先ほど views.py
に書いた index
関数が呼ばれるようになりました。
最後に、settings.py
を編集して、hello
アプリが追加されたことをプロジェクトに教えてやります。
# Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'hello', # この行を追加 ]
さて、開発用サーバを起動して http://localhost:8000/hello/
にアクセスしてみましょう。
表示されました。でもこれ、本当にただのテキストです。HTML でも何でもありません。HTML を表示させるには HttpResponse
に HTML を渡す必要があります。でも直接長々と HTML を書き込むのは面倒ですよね。そこでテンプレートの登場となります。
*1:ちなみに行末にコメントを書くときは半角スペース 2 個分開けてから書きなさい、と pep8 が教えてくれました。