巳年じゃないけど Python やろうぜ(その 12)
フォームとビューの作成
まずはビューの作成に必要なフォームから作ります。既に Django バリバリ使ってる人なら「ModelForm 使えば楽やろ」って言うと思いますが、実は ModelForm には「(自動生成される id などの)AutoField はフォーム部品化の対象外」だったりするのと、今回はいろいろと属性をいじりたいということもあって、「それだったら一から作った方がいいんじゃね ?」ということで見送りとなりました… orz
というわけで forms.py
から。
from django import forms from .models import Customer class CustomerForm(forms.Form): customer_id = forms.IntegerField( label='顧客ID', widget=forms.TextInput(attrs={'size': 5}), min_value=1, ) customer_name = forms.CharField( required=False, label='顧客名', widget=forms.TextInput(attrs={'size': 20, 'readonly': True}), ) customer_phone = forms.CharField( required=False, label='連絡先', widget=forms.TextInput(attrs={'size': 20, 'readonly': True}), )
label
は以前ご説明の通りですが、それ以外は初お目見えですね。
IntegerField
は整数値を入力するべきフォームになります。widget
はデフォルトでは NumberInput
*1なのですが、ご指名(?)で TextInput
に登場していただきます。attrs
には辞書形式で input
要素に指定する属性と属性値の組み合わせを指定します。このコードの例だと
<input id="id_customer_id" name="customer_id" size="5" type="text" required />
と同等になります。min_value
は後でバリデーションチェックに使われます。テーブルの ID なので正の数でないとおかしいですよね。だから最小値は 1 です。
customer_name
と customer_phone
は label
以外は同じですね。widget
はデフォルトの TextInput
なのですが、属性を付与したいので敢えて指定します。required
はデフォルトは True
なのですが、この二つは検索結果を埋め込むためのものなので、送信時に空になっていても良いように False
にします。また readonly
属性を付けて、このフォームからは編集できない*2ようにします。
次は views.py
です。
from django.shortcuts import get_object_or_404, render from .forms import CustomerForm from .models import Customer # Create your views here. def search(request): if request.method == 'POST': form = CustomerForm(request.POST, label_suffix='') if form.is_valid(): customer_id = form.cleaned_data['customer_id'] customer = get_object_or_404(Customer, pk=customer_id) data = { 'customer_id': customer.id, 'customer_name': customer.name, 'customer_phone': customer.phone, } form = CustomerForm(data, label_suffix='') else: form = CustomerForm(label_suffix='') return render(request, 'customer_search/search.html', { 'form': form, })
get_object_or_404
は一連のよく使われる流れを簡略化したショートカットです。これは
try: customer = Customer.objects.get(pk=customer_id) except Customer.DoesNotExist: raise Http404("Customer does not exist")
を簡略した書き方です。入力された ID を元に検索をかけて、拾った値をフォームにセットしていきます。label_suffix
は今回ちょっとお遊びで付けてみました。デフォルトだとコロンが付きますが、何も付けないように空文字をセットしてあります。
最後はテンプレート。
<!doctype html> <html> <head> <title>顧客検索</title> </head> <body> <h1>顧客検索</h1> <form method="post" action="."> {% csrf_token %} <table>{{ form }}</table> <input type="submit" value="検索"> </form> </body> </html>
form
はデフォルトだと as_table()
でレンダリングされる*3ので、table
要素の中身として記述します。それ以外は特に変わったところはありません。
django_test/urls.py
from django.conf.urls import url, include from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^hello/', include('hello.urls')), url(r'^customer_search/', include('customer_search.urls')), # 追加 ]
customer_search/urls.py
(新規作成)
from django.conf.urls import url from . import views urlpatterns = [ url(r'^$', views.search), ]
次回、ロギングの話をさらっとしてから実際に動かしてみます。
*1:localize がデフォルトで False のため。localize を True にすると TextInputになるようです。
*2:あくまでもユーザーインターフェース上の話であって、これによってデータが完全に守られるというわけではないことには注意が必要です。
*3:公式ドキュメントには「form.as_table() は print(form) と完全に同じです」と書いてある。