django備忘録2 Model Form など
Model Form
- forms.py を作成する
from django import forms #formsをimport from .models import SignUp #modelsから、classをimport class SignUpForm(forms.ModelForm): #forms.ModelForm で、modelformを継承したformclassが作成可能 class Meta: model = SignUp fields = ['email']
*ちなみに、admin.pyにも設定可能。
admin.py
class SignUpAdmin(admin.ModelAdmin): list_display = ["__str__", "timestamp", "updated"] form = SignUpForm
で、admin formにもimport可能 ※これは、formの動作を確認する時に有効!
Form Validation
- clean_emailメソッドと、 form.cleaned_data を利用して、validationを行う
forms.py
class SignUpForm(forms.ModelForm): class Meta: model = SignUp fields = ['full_name','email'] def clean_email(self): print (self.cleaned_data) #cleaned_data return "abc@ddd.com"# これは、abc@ddd.com をemailの箇所に入力するということになる。
は、保存の時に, clean_email の関数が実行される、いつか何でかわからん。 →これは、view.py→template/formタグ→action''の場合は、自分に送信→views.pyにもう一度戻ってくる?
- さらにちょっと色々項目を増やせる。 forms.py
class SignUpForm(forms.ModelForm): class Meta: model = SignUp fields = ['full_name','email'] #clean_emailメソッドで、formに入力されたemailのvalidationをする。 def clean_email(self): email = self.cleaned_data.get('email') email_base, provider = email.split("@") domain, extension = provider.split('.') if not domain == 'USC': raise forms.ValidationError("USC emailを入力してください。") if not extension == "edu": raise forms.ValidationError("有効なメールアドレスを入力してください!") return email def clean_full_name(self): full_name = self.cleaned_data.get('full_name') if not "sky" in full_name: raise forms.ValidationError("skyが含まれていません。") return full_name
最終的にこういう感じで、validationが可能。 def clean_フィールド名(self): ってのが、validationの時の関数みたい
View & Template Context
- views にcontextを設定 →templates に渡す
views.py
def home(request): title = "My Title %s" %(request.user) context = { "template_title":title, } return render(request, "home.html",context) home.html <h1>{{ template_title }}</h1>
とかそんな感じ!
- さらに一歩進んで、、、簡単なユーザー認証で、表示するページを変える 必要なのは、is_authenticated()
例えば、こんな風に、表示を変えられる
from django.shortcuts import render # Create your views here. def home(request): title = "ようこそ!ユーザー登録をお願いします!" if request.user.is_authenticated(): title = "My Title %s" %(request.user) context = { "template_title":title, } return render(request, "home.html",context)
・view templates の関係のちょっとしたtips contextに設定しなくても、user, request.userは、templateに反映可能。 それが可能なのは、settings.py に入っている、TEMPLATESの、 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', あたりらしい
{{ user }} {{ request.user }}
で、反映されるのを確認。
- Form in View views.pyの中に、forms.py のformを入れる→contextで、templatesに反映
views.py
form = SignUpForm() context = { "form":form } って感じで、contextに渡す。 homes.html <form method='' action=''> {{ form }} <input type='submit' value='Sign Up'/> </form>
って感じで、form タグの中に、設定する。
登録などのform のmethodは、基本的にPOSTを使う。 検索の時とかは、GET
ただ、methodが、POSTの場合は、{% csrf_token %} が必要。
<form method='POST' action=''>{% csrf_token %} {{ form }}
こんな感じで、1行いれるだけ!
- views.pyで、
views.py
if request.method == "POST": print (request.POST)
と入れると、request.POSTの内容が表示される。 つまり、フォームの流れとしては、、、
urls.py → views.py(form)→templates(home.html)で、home.htmlのフォームに入力→action="" の先に送付。つまり、home.htmlの元のデータ(views.py(form.py))に行く!views.pyは、request.POSTを持った、formsを、forms.save()で、modelsに保存するという感じの流れなのか?
- だから、
views.py
form = SignUpForm(request.POST or None)
をセットして、POSTの内容を渡す
- save() メソッドはオプション commit キーワード引数を持っています。こ の引数には True または False を指定します。 save() を commit=False で呼び出すと、データベースに保存する前のモデルオブジェクト を返します。
if form.is_valid(): instance = form.save(commit=False) if instance.full_name == None: instance.full_name = "Justin" instance.save() print (instance.email) print (instance.timestamp)
この例だと、instance = form.save(commit=False) 未保存の状態 instance.save()で保存というstepを踏むということ。
- POSTした後は、再度viewに戻ってきて、処理を行うため、送信後のtemplatesに渡すcontextも微妙に変えて渡すことができる。
例えば、以下のとおりです! context で、新しい変数をtemplatesに渡してる viewは、modelよりも小さくが基本みたいだから、modelにこの辺は組み込んだ方がいいのかもしれん。
views.py
from django.shortcuts import render from .forms import SignUpForm # Create your views here. def home(request): title = "ようこそ!ユーザー登録をお願いします!" if request.user.is_authenticated(): title = "My Title %s" %(request.user) form = SignUpForm(request.POST or None) context = { "title":title, "form":form, } if form.is_valid(): # form.save() #print (request.POST['email']) --"これはやっちゃダメ。POST全部が上書きされてしまう。" instance = form.save(commit=False) full_name = form.cleaned_data.get("full_name") if not full_name: full_name = "New Full Name" instance.full_name = full_name # instance = form.save(commit=False) # if not instance.full_name: # instance.full_name = "Justin" instance.save() context = { "title": "Thank you", } return render(request, "home.html",context)