目录
如何获取url的信息
HttpRequest 对象中有一些关于当前所请求 URL 的信息
其他可用来反爬的信息
request.META 的值是一个 Python 字典,包含请求的所有 HTTP 首部,例如用户的 IP 地址和用户代理(useragent,通常是 Web 浏览器的名称和版本)。注意,具体包含哪些首部取决于用户发送了什么首部,以及Web 服务器返回了什么首部。这个字典中常见的几个键有:
• HTTP_REFERER :入站前的 URL(可能没有)。(注意,要使用错误的拼写,即 REFERER 。)
• HTTP_USER_AGENT :浏览器的用户代理(可能没有)。例如: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.8.1.17) Gecko/20080829 Firefox/2.0.0.17" 。
• REMOTE_ADDR :客户端的 IP 地址,例如 "12.345.67.89" 。(如果请求经由代理,这个首部的值可能是一组 IP 地址,以逗号分隔,例如 "12.345.67.89,23.456.78.90" 。)
注意,因为 request.META 是个普通的 Python 字典,所以尝试访问不存在的键时,抛出 KeyError 异常。
# 不好
def ua_display_bad(request):
ua = request.META['HTTP_USER_AGENT'] # 可能抛出 KeyError
return HttpResponse("Your browser is %s" % ua)
# 好(版本 1)
def ua_display_good1(request):
try:
ua = request.META['HTTP_USER_AGENT']
except KeyError:
ua = 'unknown'
return HttpResponse("Your browser is %s" % ua)
# 好(版本 2)
def ua_display_good2(request):
ua = request.META.get('HTTP_USER_AGENT', 'unknown')
return HttpResponse("Your browser is %s" % ua)
下面是一个简单的视图,显示 request.META 中的所有信息,以便查阅。
def display_meta(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>' % '\n'.join(html))
view
{% extends "base.html" %}
{% block title %}My helpful display meta{% endblock %}
{% block h1 %}The display meta{% endblock %}
{% block item %}
<ul>
{% for item in item_list %}
<li>{{ item }}</li>{% endfor %}
</ul>
{% endblock %}
结果如下
一个简单的表单处理
如下配置
urls.py
url(r'^search-form/$', search_form),
url(r'^search/$', search),
views.py
def search_form(request):
return render(request, 'search_form.html')
def search(request):
if 'q' in request.GET:
q = request.GET['q']
books = Book.objects.filter(title__icontains=q)
return render(request, 'search_results.html',
{'books': books, 'query': q})
else:
message = 'You submitted an empty form.'
return HttpResponse(message)
search_form.html
<html>
<head>
<title>Search</title>
</head>
<body>
<form action="/search/" method="get">
<input type="text" name="q">
<input type="submit" value="Search">
</form>
</body>
</html>
search_results.html
<html>
<head>
<title>Book Search</title>
</head>
<body>
<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 %}
</body>
</html>
简单的验证
def search(request):
error = []
if 'q' in request.GET:
q = request.GET['q']
if not q:
error.append('请填写内容')
elif len(q) > 20 or len(q) == 0:
error.append('字符串超过20')
else:
books = Book.objects.filter(title__icontains=q)
return render(request, 'search_results.html',{'books': books, 'query': q})
return render(request, 'search_form.html',{'error': error})
<html>
<head>
<title>Search</title>
</head>
<body>
{% if error %}
{% for error_ in error %}
<li>{{ error_ }}</li>
{% endfor %}
{% endif %}
<form action="/search/" method="get">
<input type="text" name="q">
<input type="submit" value="Search">
</form>
</body>
</html>
第一个表单类
Django 自带了一个表单库, django.forms ,它能处理本章所述的多数问题,从显示 HTML 表单到验证,都能胜任。下面我们使用这个 Django 表单框架为应用程序构建一个联系表单。
在 views.py 文件所在的目录( mysite )中创建 forms.py文件,然后输入下述内容:
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField()
email = forms.EmailField(required=False)
message = forms.CharField()
打印查看
>>> from mysite.forms import ContactForm
>>> f = ContactForm()
>>> print(f.as_p())
>>> <p><label for="id_subject">Subject:</label> <input type="text" name="subject" required id=
"id_subject" /></p>
<p><label for="id_email">Email:</label> <input type="email" name="email" id="id_email" /><
/p>
<p><label for="id_message">Message:</label> <input type="text" name="message" required id=
"id_message" /></p>
>>> print(f['subject'])
<input id="id_subject" name="subject" type="text" />
>>> print f['message']
<input id="id_message" name="message" type="text" />
在视图中使用表单对象
views.py
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
......
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>
urls.py
# ...
from mysite.views import hello, current_datetime, hours_ahead, contact
urlpatterns = [
# ...
url(r'^contact/$', contact),
]
这个表单使用 POST 处理(要修改数据),因此要关心跨站请求伪造(Cross Site Request Forgery,CSRF)。
幸好,我们无需太过担心,因为 Django 提供了非常易用的防护系统。简单来说,所有通过 POST 指向内部
URL 的表单都应该使用 {% csrf_token %} 模板标签。
改变字段的渲染方式
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField()
email = forms.EmailField(required=False)
message = forms.CharField(widget=forms.Textarea)
设定最大长度
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(max_length=10)
email = forms.EmailField(required=False)
message = forms.CharField(widget=forms.Textarea)
超过10长度就会无法输入
设定初始值
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': 'max 10'}
)
return render(request, 'contact_form.html', {'form': form})
自定义验证规则
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(max_length=10)
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
Django 的表单系统会自动查找名称以 clean_ 开头、以字段名结尾的方法。如果存在这样的方法,在验证过程中调用。这里, clean_message() 方法会在指定字段的默认验证逻辑(这个 CharField 是必填的)执行完毕后调用。
指定标注
email = forms.EmailField(required=False, label='Your e-mail address')