前回まで
前回はUser Objectについて話しましたので、今回はメッセージの表示とか、あとtemplatesの中にあるHTMLページをまとめる方法を書きたいと思います。Registerシステムがあれば、Login成功とか、Login失敗するときは色んな表示メッセージがくるじゃないですか?
流れ
- view.pyでLoginの動作などをしたのあとのメッセージ追加
- templates の中でメッセージ追加
- templatesのHTMLをグループ化する
view.pyでLoginの動作などをしたのあとのメッセージ追加
まず messages frameworkを見てきましょう。
WebをみるときたまにPOP-UPをみたことがありますか?一回だけでClickすればなくなる。それはこのmessages frameworkの役目ですね。中にはレベルに分けておいて(info,warning,errorなど)
メッセージのレベルは以下のようになります:
DEBUG:いわゆる開発中のとき使われてるのMessageですね。
INFO:Userにお知らせする。
SUCCESS:Userがやってたアクション成功した(Loginしましたとか)
WARNING:エラーにはならなく実行しましたが、まぁ、英語通り、警告って感じですね。
ERROR:アクション実行できませんでした。なにかエラーが起こってる。
以下の例は、
User登録成功:info,success
User 登録失敗:error
User Login in成功:info
あと前回説明抜けところがありますね。
Form.is_valid()
これを使うことによってFormのデータが有効かどうかをCheckしてくれますね~もし無効なデータがあるならFalseに戻し、OKなデータならTrueが戻してくれます。
Form.cleaned_data
DjangoのForm FrameworkはデータがOKかどうかを判断するだけではなく、データ自体も“綺麗”にしてくれます、データを一致のFormatに変更しれくれます。例えば、DateFieldをPythonのdatetime.date Objectに変更し、“'1994-07-15'”がもらってでもちゃんとPythonのObjectに変更しれくれます。多分言葉だけ説明してもちょっとわかりつらいから、Shellから説明します。
python manage.py shell
djangoからforms をImportし、新しいforms を1個作ります。
fieldsは文字200までのsubjとメールアドレスですね。
In [6]: from django import forms
In [7]: class form1(forms.Form):
...: subj=forms.CharField(max_length=100)
...: email=forms.EmailField()
データ新しく作ります。そして新しいform1 “f”が作りました。
In [8]: data1={'subj':'test1',
...: 'email':'abc@example.com'}
In [9]: f=form1(data1)
ではまず先のis_valid()を試してみよう。
うんうん、OKですね。無効な入力が入ってません。
In [13]: f.is_valid()
Out[13]: True
次はclean()を使ってみます。
うん…あまり変わらないですね。
In [14]: f.clean()
Out[14]: {'subj': 'test1', 'email': 'abc@example.com'}
じゃ今度はもう一つのform “form2”を作ってみますね。
文字200まで、メールアドレス、更に時間の入力も入ってます。
In [27]: class form2(forms.Form):
...: subj=forms.CharField(max_length=100)
...: email=forms.EmailField()
...: date=forms.DateField()
ではでは、また新しいデータを作り、f2が定義されました。
In [28]: data2={'subj':'subj2',
...: 'email':'example@example.com',
...: 'date':'1998-02-11'
...: }
In [29]: f2=form2(data2)
まずデータが有効かどうかをCheckします。
In [30]: f2.is_valid()
Out[30]: True
clean()かけるまえのデータは、辞書ですね。
In [42]: f2.data
Out[42]: {'subj': 'subj2', 'email': 'example@example.com', 'date': '1998-02-11'}
次はclean()をかけてみます。
出力の変化見えましたか?dateの項目がdatetime.dateになりました!
In [31]: f2.clean()
Out[31]:
{'subj': 'subj2',
'email': 'example@example.com',
'date': datetime.date(1998, 2, 11)}
In [33]: f2.cleaned_data.get('date')
Out[33]: datetime.date(1998, 2, 11)
念のため、Typeを確認しよう。OKですね!
In [43]: d=f2.cleaned_data.get('date')
In [44]: d
Out[44]: datetime.date(1998, 2, 11)
In [45]: type(d)
Out[45]: datetime.date
最後はメールアドレスのところに変なもの入れてみよう。
In [36]: data3={'subj':'subj2',
...: ...: 'email':'examplexample.com',
...: ...: 'date':'1998-02-11'
...: ...: }
is_valid() はちゃんとFalse返してくれたね~
In [37]: f3=form2(data3)
In [38]: f3.is_valid()
Out[38]: False
話が長くなりましたが、コードは以下になります:
from django.shortcuts import render,redirect
from django.http import HttpResponse
from .models import mydb
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth import login,logout,authenticate
from django.contrib import messages
def homepage(request):
return render(
request=request
,template_name="helloworld/home.html"
,context={"mydb":mydb.objects.all}
)
def register(request):
if request.method == "POST":
form=UserCreationForm(request.POST)
if form.is_valid():
user=form.save()
username=form.cleaned_data.get('username') #
messages.success(request,'Your account is Created,{}.'.format(username))#
login(request,user)
messages.info(request,'Logged In,{}.'.format(username))#
return redirect("helloworld:homepage")
else:
for msg in form.error_messages:
print(form.error_messages[msg])
messages.error(request,'some error,{}.',format(form.error_messages[msg]))#
form =UserCreationForm
return render(
request=request
,template_name="helloworld/register.html"
,context={"form":form}
)
templates の中でメッセージ追加
次はheader.htmlの中にmessageを入れます。
POP UP Messageの出し方はFrameworkによって違いますので、ここはw3.cssの参考例になります。views.pyからmessage をもらって、このmessageの属性によって出てくるのメッセージがわかります。
<head>
{% load static %}
<link rel='stylesheet' href="{% static "helloworld/w3c.css"%}">
</head>
<body>
<div class="w3-bar w3-border w3-light-grey">
<a href="/" class="w3-bar-item w3-button w3-mobile">Home</a>
<a href="/register" class="w3-bar-item w3-button w3-mobile">Register</a>
<a href="/login" class="w3-bar-item w3-button w3-mobile">login</a>
</div>
{% if messages %}
{% for message in messages %}
{% if message.tags == 'success'%}
<div class="w3-panel w3-green">
<h3>success</h3>
<p>{{message}}</p>
<span onclick="this.parentElement.style.display='none'"
class="w3-button w3-display-topright"
>×</span>
</div>
{% elif message.tags == 'info'%}
<div class="w3-panel w3-blue">
<h3>Info</h3>
<p>{{message}}}</p>
<span onclick="this.parentElement.style.display='none'"
class="w3-button w3-display-topright"
>×</span>
</div>
{% elif message.tags == 'warning'%}
<div class="w3-panel w3-red">
<h3>Warning</h3>
<p>{{message}}</p>
<span onclick="this.parentElement.style.display='none'"
class="w3-button w3-display-topright"
>×</span>
</div>
{% elif message.tags == 'error'%}
<div class="w3-panel w3-yellow">
<h3>Error</h3>
<p>{{message}}</p>
<span onclick="this.parentElement.style.display='none'"
class="w3-button w3-display-topright"
>×</span>
</div>
{% endif %}
{% endfor %}
{% endif %}
{% block content%}}
{% endblock%}
</body>
Userを登録成功したら、SuccessとInfoのメッセージがちゃんと出ましたね!
もしなにかの入力間違いだったら…
templatesのHTMLをグループ化する
こっちらは先までのheader.htmlですが、めっちゃ長いと思いませんか?
ここで”include”というものを紹介します。
ここからみると、Navバーがあって、Messageのエリアもあっての感じですね。
じゃこんな風に分けたらどうです?Layoutも綺麗になりますね。
nav.htmlを開いて、header.htmlの中にあるNavの部分をここで貼り付けます。
<nav>
<div class="w3-bar w3-border w3-light-grey">
<a href="/" class="w3-bar-item w3-button w3-mobile">Home</a>
<a href="/register" class="w3-bar-item w3-button w3-mobile">Register</a>
<a href="/login" class="w3-bar-item w3-button w3-mobile">login</a>
</div>
</nav>
message.htmlを開いて、先POPUPの部分だけここに貼り付けます。
{% if messages %}
{% for message in messages %}
{% if message.tags == 'success'%}
<div class="w3-panel w3-green">
<h3>success</h3>
<p>{{message}}</p>
<span onclick="this.parentElement.style.display='none'"
class="w3-button w3-display-topright"
>×</span>
</div>
{% elif message.tags == 'info'%}
<div class="w3-panel w3-blue">
<h3>Info</h3>
<p>{{message}}}</p>
<span onclick="this.parentElement.style.display='none'"
class="w3-button w3-display-topright"
>×</span>
</div>
{% elif message.tags == 'warning'%}
<div class="w3-panel w3-red">
<h3>Warning</h3>
<p>{{message}}</p>
<span onclick="this.parentElement.style.display='none'"
class="w3-button w3-display-topright"
>×</span>
</div>
{% elif message.tags == 'error'%}
<div class="w3-panel w3-yellow">
<h3>Error</h3>
<p>{{message}}</p>
<span onclick="this.parentElement.style.display='none'"
class="w3-button w3-display-topright"
>×</span>
</div>
{% endif %}
{% endfor %}
{% endif %}
最後に、header.htmlは先作ったのものを“include”すれば、完成です。
<head>
{% load static %}
<link rel='stylesheet' href="{% static "helloworld/w3c.css"%}">
</head>
{% include "helloworld/includes/nav.html" %}
{% include "helloworld/includes/message.html" %}
{% block content%}}
{% endblock%}
</body>
以上、お疲れ様です!