疯狂的暑假学习之 Django学习笔记(五)—— 表单
參考:《The Django Book》 第7章
1. HttpRequest对象的信息
request.path 除域名以外的请求路径,斜杠开头 “/hello/”
request.get_host() 主机名 “127.0.0.1:8000” or “www.xxxx.com”
request.get_full_path() 请求路径,可能包括查询字符串 “/hello/?
print=true”
request.is_secure() 是否通过Https訪问 是为True。否为False
request.META 一个字典。包括本次Http请求的Header信息 比如 REMOTE_ADDR 表示clientip,
HTTP_USER_AGENT表示用户浏览器user-agent字符串
HTTP_REFERER表示进站前连接网页
request.POST 一个类字典对象保存html中<form>标签提交的内容
request.GET 一个类字典对象保存html中<form>标签提交的内容或者URL中的查询字符串
样例:显示request.META 中的全部信息
在view.py中增加以下代码。并在urls.py加上相应的URLpattern
def test(request): values = request.META.items() values.sort() html = [] for k,v in values: html.append('<tr><td>%s</td><td>%s</td></tr>' % (k,v)) return HttpResponse('<table>%s</table>' % ' '.join(html))
2. 一个简单的表单处理
在templates中创建search_form.html模板:
<html> <head> <title>Search</title> </head> <body> {% if error %} <p style="color: red;">Please submit a search term.</p> {% endif %} <form action='' method='get'> <input type='text' name='q'> <input type='submit' value='Search'> </form> </body> </html>
当中action='' 表示表单将提交给与当前页面同样的URL
再加入search_results.html
<p>You searched for: <strong>{{ query }}</strong></p> {% if books %} <p>Found {{ books|length }} book{{ books|pluralize }}.</p> <ul> {% for book in books %} <li>{{ book.title }}</li> {% endfor %} </ul> {% else %} <p> No books matched your search criteria. </p> {% endif %}
在view.py中加入:
def search(request): error = False if 'q' in request.GET: q = request.GET['q'] if not q: error = True else: books = Book.objects.filter(title__icontains=q) return render_to_response('search_results.html', {'books':books,'query':q}) return render_to_response('search_form.html', {'error':error})
当中Book.objects.filter(title__icontains=q) 是用来获取数据库中标题包括q的书籍。icontains是一个查询keyword。
在urls.py 中加入
(r'search/$',search),
然后在浏览器输入 http://127.0.0.1:8000/search/ 能够看到一个简单的搜索界面。
3. 简单的验证
能够用Javascript在client浏览器进行验证。但可能有些人会将Javascript关闭。而且另一些怀有恶意的用户会尝试提交非法的数据来探測是否有能够攻击的机会。所以除了用Javascript在client浏览器进行验证外,还须要在server验证一次。上面的代码,仅仅对 输入为空做了验证。以下加入一个验证搜索keyword是否小于20个字符的验证。
样例:
改动view.py
def search(request): errors = [] if 'q' in request.GET: q = request.GET['q'] if not q: errors.append('Enter a search term') elif len(q) > 20: errors.append('Please enter at most 20 characters.') else: books = Book.objects.filter(title__icontains=q) return render_to_response('search_results.html', {'books':books,'query':q}) return render_to_response('search_form.html', {'errors':errors})
改动 search_form.html :
<html> <head> <title>Search</title> </head> <body> {% if errors %} {% for error in errors%} <p style="color: red;">{{ error }}</p> {% endfor %} {% endif %} <form action='' method='get'> <input type='text' name='q'> <input type='submit' value='Search'> </form> </body> </html>
4. 编写Contact表单
一个较为复杂的样例:这个表单包含用户提交的反馈信息,一个能够选择填不填的e-mail地址。
view.py 中加入:
def contact(request): errors = [] if request.method == 'POST': if not request.POST.get('subject', ''): errors.append('Enter a subject.') if not request.POST.get('message', ''): errors.append('Enter a message.') if request.POST.get('email') and '@' not in request.POST['email']: errors.append('Enter a valid e-mail address.') if not errors: send_mail( request.POST['subject'], request.POST['message'], request.POST.get('email', 'noreply@example.com'), ['siteowner@example.com'], ) return HttpResponseRedirect('/contact/thanks/') return render_to_response('contact_form.html', { 'errors': errors, 'subject': request.POST.get('subject', ''), 'message': request.POST.get('message', ''), 'email': request.POST.get('email', ''), },context_instance=RequestContext(request))
用POST不用GET,由于这个表单会有一个server端的操作:send_mail。
在templates中加入contact_form.html :
<html> <head> <title>Contact us</title> </head> <body> <h1>Contact us</h1> {% if errors %} <ul> {% for error in errors %} <li>{{ error }}</li> {% endfor %} </ul> {% endif %} <form action="/contact/" method="post"> {% csrf_token %} <p>Subject: <input type="text" name="subject" value="{{ subject }}"></p> <p>Your e-mail (optional): <input type="text" name="email" value="{{ email }}"></p> <p>Message: <textarea name="message" rows="10" cols="50">{{ message }}</textarea></p> <input type="submit" value="Submit"> </form> </body> </html>
这个样例看起来杂乱。解决方法看以下用forms。
5. from类
上面的那个样例,看起来杂乱,而且easy出错。
Django带有一个form库,称为django.forms,这个库能够处理HTML表单显示以及验证。
新建 forms.py 增加
from django import forms class ContactForm(forms.Form): subject = forms.CharField() email = forms.EmailField(required=False) message = forms.CharField()
非常像模块中用的语法。默认是每一个字段必填的,假设要是能够不填的要指定required=False,就像上面的email字段一样。
来看看forms类究竟是什么:它做的第一个是就是将自己显示成HTML
>>> from contact.forms import ContactForm >>> f = ContactForm() >>> print f <tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" name="subject" type="text" /></td></tr> <tr><th><label for="id_email">Email:</label></th><td><input id="id_email" name="email" type="email" /></td></tr> <tr><th><label for="id_message">Message:</label></th><td><input id="id_message" name="message" type="text" /></td></tr>
默认是依照 <table> 现实输出的,还能够:
>>> print f.as_ul() <li><label for="id_subject">Subject:</label> <input id="id_subject" name="subject" type="text" /></li> <li><label for="id_email">Email:</label> <input id="id_email" name="email" type="email" /></li> <li><label for="id_message">Message:</label> <input id="id_message" name="message" type="text" /></li> >>> print f.as_p() <p><label for="id_subject">Subject:</label> <input id="id_subject" name="subject" type="text" /></p> <p><label for="id_email">Email:</label> <input id="id_email" name="email" type="email" /></p> <p><label for="id_message">Message:</label> <input id="id_message" name="message" type="text" /></p>
还能够这样显示
>>> print f['subject'] <input id="id_subject" name="subject" type="text" />
forms对象做的第二件事是校验数据。如今先加入数据:
>>> f = ContactForm({'subject': 'Hello', 'email': 'adrian@example.com', 'message': 'Nice site!'}) >>>
一旦对一个forms对象实体赋值。就能够得到一个绑定的form:
>>> f.is_bound True >>>
还能够验证数据是否合法
>>> f.is_valid() True >>>
假设合法为True。假设不合法为False。如:假设subject或者,essage为空。f.is_valid()就会返回False
也能够查看每一个字段的error
>>> f = ContactForm({'subject': 'Hello', 'message': ''}) >>> f['message'].errors [u'This field is required.'] >>> f['subject'].errors [] >>>
还能够通过errors属性查看错误
>>> f.errors {'message': [u'This field is required.']} >>>
假设forms合法,他就有一个cleaned_data属性,将数据转化成Python类型数据,存放在cleaned_data中。
比如:假设是字符串就会被清理成Unicode对象,整数会被清理成Python整数,日期清理成datetime.date型对象
>>> f = ContactForm({'subject': 'Hello', 'email': 'adrian@example.com', 'message': 'Nice site!'}) >>> f.is_valid() True >>> f.cleaned_data {'message': u'Nice site!', 'email': u'adrian@example.com', 'subject': u'Hello'}
6. 在视图中使用Form对象
样例:
view.py
from django.shortcuts import render from contact.forms import ContactForm from django.http import HttpResponseRedirect from django.core.mail import send_mail def contact(request): if request.method == 'POST': form = ContactForm(request.POST) if form.is_valid(): cd = form.cleaned_data send_mail( cd['subject'], cd['message'], cd.get('email', 'noreply@example.com'), ['siteowner@example.com'], ) return HttpResponseRedirect('/contact/thanks/') else: form = ContactForm() return render(request, 'contact_form.html', {'form': form})
contact_form.html
<html> <head> <title>Contact us</title> </head> <body> <h1>Contact us</h1> {% if form.errors %} <p style="color: red;"> Please correct the error{{ form.errors|pluralize }} below. </p> {% endif %} <form action="" method="post"> <table> {{ form.as_table }} </table> {% csrf_token %} <input type="submit" value="Submit"> </form> </body> </html>
上面的样例有个缺陷,message这个表单变成了 input type=“text”。
我们能够通过设置widget来改动它:
from django import forms class ContactForm(forms.Form): subject = forms.CharField() email = forms.EmailField(required=False) message = forms.CharField(widget=forms.Textarea)
还能够设置最大长度
设置max_length
from django import forms class ContactForm(forms.Form): subject = forms.CharField(max_length=20) email = forms.EmailField(required=False) message = forms.CharField(widget=forms.Textarea)
设置初始值:
在view.py中ContectForm中加入 initial 參数:
from django.shortcuts import render from contact.forms import ContactForm from django.http import HttpResponseRedirect from django.core.mail import send_mail def contact(request): if request.method == 'POST': form = ContactForm(request.POST) if form.is_valid(): cd = form.cleaned_data send_mail( cd['subject'], cd['message'], cd.get('email', 'noreply@example.com'), ['siteowner@example.com'], ) return HttpResponseRedirect('/contact/thanks/') else: form = ContactForm( initial={'subject': 'AAAAAA'} ) return render(request, 'contact_form.html', {'form': form})
注意:默认值与表单传入是有差别的。差别在于,假设只传入默认值,是没有绑定的。
7. 自己定义校验规则
比如我们须要加入 message 字段有一个额外的校验,我们就要摘forms类中加入 clean_message() 方法
样例:加入校验 messge中的单词数量(注意不是字母数量。看 split() )要不少于4个.
from django import forms class ContactForm(forms.Form): subject = forms.CharField(max_length=100) email = forms.EmailField(required=False) message = forms.CharField(widget=forms.Textarea) def clean_message(self): message = self.cleaned_data['message'] num_words = len(message.split()) if num_words < 4: raise forms.ValidationError("Not enough words!") return message