2.0里的内容
path转换器
str,int,uuid,/
slug:可理解为注释、后缀、附属等解释性字符
匹配任何ASCII字符以及连接符和下划线
自定义path转换器类
class FourDigitYearConverter:
regex = '[0-9]{4}'#类属性regex:一个字符串形式的正则表达式属性
def to_python(self, value):
return int(value)#数据转换失败,它必须弹出ValueError
def to_url(self, value):
return '%04d' % value#数据类型转换为一段url的方法
使用正则表达式re_path
#错误页面
#可以在url里重新定义这个,view.py里加新模板逻辑即可
请求不成功,系统自动返回一个错误页面
handler400 —— django.conf.urls.handler400
handler403 —— django.conf.urls.handler403
handler404 —— django.conf.urls.handler404
handler500 —— django.conf.urls.handler500
手动处理转到错误页面
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/results.html', {'question': question})
url路由转发include
1. include('apps.help.urls')遇到include会去掉URL中匹配的部分并将剩下的字符串发送给include的URLconf,转发到二级路由
2. include(extra_url列表)相当于把二级路由模块内的代码写到根路由模块里,不推荐
3. 被转发的URLconf会收到来自父URLconf捕获的所有参数url(r'^(?P<username>\w+)/blog/', include('foo.urls.blog#username可以传去blog对应的url
4. 嵌套参数url(r'comments/(?:page-(?P<page_number>\d+)/)?$', comments)
5. 向视图传递额外参数url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'})
6. 传递额外的参数给include()参数会传递给include指向的urlconf中的每一行url(r'^blog/', include('inner'), {'blogid': 3})#bug在于有些不要此参数的也会赋值
url反向解析
安全、可靠、自适应的机制,当修改URLconf中的代码后,无需在项目源码中大范围搜索、替换失效的硬编码URL
通过这个name参数,可以反向解析URL、反向URL匹配、反向URL查询或者简单的URL反查
url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive')
<li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
def redirect_to_year(request):
# ...
year = 2006
# ...注意参数的传递方法
return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))
命名空间
app_name='xxx'
url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail')
##'polls:index'将解析到'author-polls'实例的index视图
view:reverse('polls:index', current_app=self.request.resolver_match.namespace)
template: {% url 'polls:index' %}
include一个包含嵌套命名空间数据的对象。
如果你include()一个url()实例的列表,那么该对象中包含的URL将添加到全局命名空间。
但是,你也可以include()一个2元组
polls_patterns = ([
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'),
], 'polls')#元祖
urlpatterns = [
url(r'^polls/', include(polls_patterns)),
]
@@@view
$基础响应
HttpResponse('html')#status=200
HttpResponseNotFound('html')
from django.http import HttpResponse, HttpResponseNotFound
from django.http import Http404
from django.shortcuts import render
from polls.models import Poll
from django.shortcuts import get_object_or_404
def detail(request, poll_id):
try:
p = Poll.objects.get(pk=poll_id)#获取表poll内容
except Poll.DoesNotExist:#表poll不存在
raise Http404("Poll does not exist")#404
return render(request, 'polls/detail.html', {'poll': p})#默认空字典
#my_object = get_object_or_404(MyModel, pk=1)#model
return redirect(reverse('some-view-name'), foo='bar')#reverse_model
#queryset = Book.objects.filter(title__startswith='M')#queryset
#get_object_or_404(queryset, pk=1)
#get_object_or_404(Book, title__startswith='M', pk=1)#简化
$get_object_or_404(klass, args, *kwargs)[source]#get
这个方法,非常有用,请一定熟记。常用于查询某个对象,找到了则进行下一步处理,如果未找到则返回404页面
$my_objects = get_list_or_404(MyModel, published=True)#filter
返回一个给定模型管理器上filter()的结果,并将结果映射为一个列表,结果为空则弹出Http404异常
$redirect重定向
调用对象的get_absolute_url()方法来重定向URL
object = MyModel.objects.get(...)
return redirect(object)
return redirect(object, permanent=True)#永久重定向
传递视图名,使用reverse()方法反向解析url
return redirect('some-view-name', foo='bar')#视图名
return redirect('/some/url/')#硬编码
return redirect('https://example.com/')#完整url
= = =
- HttpRequest
属性
HttpRequest.scheme求的协议种类
HttpRequest.body表示原始HTTP请求的正文
HttpRequest.path表示当前请求页面的完整路径,但是不包括协议名和域名
HttpRequest.path_info包含路径信息部分,WSGIScriptAlias
HttpRequest.method方法'GET'POST
HttpRequest.encoding数据的编码方式DEFAULT_CHARSET
HttpRequest.content_type请求MIME类型
HttpRequest.content_params在CONTENT_TYPE标题中的键/值参数字典
HttpRequest.GET包含GET请求中的所有参数-字典
HttpRequest.POST包含POST请求的参数与表单数据-字典
HttpRequest.COOKIES所有Cookie信息的字典。 键和值都为字符串-字典-cookie不安全敏感不要写入
HttpRequest.FILES包含所有上传的文件数据-字典-键<input type="file" name="" />中的name属性值-值UploadedFile
HttpRequest.METAHTTP头部信息-字典-可用的头部信息取决于客户端和服务器
CONTENT_LENGTH —— 请求正文的长度(以字符串计)。
CONTENT_TYPE —— 请求正文的MIME类型。
HTTP_ACCEPT —— 可接收的响应Content-Type。
HTTP_ACCEPT_ENCODING —— 可接收的响应编码类型。
HTTP_ACCEPT_LANGUAGE —— 可接收的响应语言种类。
HTTP_HOST —— 客服端发送的Host头部。
HTTP_REFERER —— Referring页面。
HTTP_USER_AGENT —— 客户端的user-agent字符串。
QUERY_STRING —— 查询字符串。
REMOTE_ADDR —— 客户端的IP地址。想要获取客户端的ip信息,就在这里!
REMOTE_HOST —— 客户端的主机名。
REMOTE_USER —— 服务器认证后的用户,如果可用。
REQUEST_METHOD —— 表示请求方法的字符串,例如"GET" 或"POST"。
SERVER_NAME —— 服务器的主机名。
SERVER_PORT —— 服务器的端口(字符串)。
HttpRequest.current_app表示当前app的名字。url模板标签将使用其值作为reverse()方法的current_app参数
HttpRequest.urlconf设置当前请求的根URLconf,用于指定不同的url路由进入口,这将覆盖settings中的ROOT_URLCONF设置
中间件设置的属性
from django.utils.deprecation import MiddlewareMixin
HttpRequest.session#SessionMiddleware中间件:一个可读写的,类似字典的对象,表示当前会话
HttpRequest.site#CurrentSiteMiddleware中间件:get_current_site()方法返回的Site或RequestSite的实例,代表当前站点是哪个
HttpRequest.user#AuthenticationMiddleware中间件:表示当前登录的用户的AUTH_USER_MODEL的实例未登录AnonymousUser
#if request.user.is_authenticated:判断当前用户是否合法用户
#方法
HttpRequest.get_host()[source]根据HTTP_X_FORWARDED_HOST和HTTP_HOST头部信息获取请求的原始主机
HttpRequest.get_port()[source]
使用META中HTTP_X_FORWARDED_PORT和SERVER_PORT的信息返回请求的始发端口
HttpRequest.get_full_path()[source]返回包含完整参数列表的path。例如:/music/bands/the_beatles/?print=true
HttpRequest.build_absolute_uri(location)[source]返回location的绝对URI形式。若location没有提供,则使用request.get_full_path()的值
HttpRequest.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)[source]
从已签名的Cookie中获取值,如果签名不合法则返回django.core.signing.BadSignature。
可选参数salt用来为密码加盐,提高安全系数。 max_age参数用于检查Cookie对应的时间戳是否超时
HttpRequest.is_secure()[source]
如果使用的是Https,则返回True,表示连接是安全的
HttpRequest.is_ajax()[source]
如果请求是通过XMLHttpRequest生成的,则返回True
从HttpRequest实例读取文件数据,可以将HttpRequest实例直接传递到XML解析器,例如ElementTree
HttpRequest.read(size=None)[source]
HttpRequest.readline()[source]
HttpRequest.readlines()[source]
HttpRequest.xreadlines()[source]
HttpRequest.iter()
import xml.etree.ElementTree as ET
for element in ET.iterparse(request):
process(element)
= = =
###QueryDict
request.POST或request.GET的QueryDict都是不可变,只读的
QueryDict.copy()可以获取一个拷贝然后进行修改
QueryDict.init(query_string=None, mutable=False, encoding=None)[source]
QueryDict('a=1&a=2&c=3',mutable=True)#实例化可以修改的对象
<QueryDict: {'a': ['1', '2'], 'c': ['3']}>
QueryDict.update(other_dict)用新的QueryDict或字典更新当前QueryDict。类似dict.update(),但是追加内容,而不是更新并替换它们,且查询只返回最新那个
>>> q = QueryDict('a=1', mutable=True)
>>> q.update({'a': '2'})
>>> q.getlist('a')
['1', '2']
>>> q['a'] #'2' returns the last
QueryDict.items()类似dict.items(),如果有重复项目,返回最近的一个,而不是都返回
>>> q = QueryDict('a=1&a=2&a=3')
>>> q.items()
[('a', '3')]
QueryDict.values()类似dict.values(),但是只返回最近的值
>>> q = QueryDict('a=1&a=2&a=3')
>>> q.values()#['3']
QueryDict.getlist(key, default=None)返回键对应的值列表。 如果该键不存在并且未提供默认值,则返回一个空列表
QueryDict.setlist(key, list_)[source]为list_设置给定的键
QueryDict.appendlist(key, item)[source]将键追加到内部与键相关联的列表中
QueryDict.setdefault(key, default=None)[source]类似dict.setdefault(),为某个键设置默认值
QueryDict.setlistdefault(key, default_list=None)[source]类似setdefault(),除了它需要的是一个值的列表而不是单个值
QueryDict.lists()类似items(),只是它将其中的每个键的值作为列表放在一起
>>> q = QueryDict('a=1&a=2&a=3')
>>> q.lists()#[('a', ['1', '2', '3'])]
QueryDict.pop(key)[source]返回给定键的值的列表,并从QueryDict中移除该键。 如果键不存在,将引发KeyError
>>> q = QueryDict('a=1&a=2&a=3', mutable=True)
>>> q.pop('a')#['1', '2', '3']
QueryDict.popitem()[source]删除QueryDict任意一个键,并返回二值元组,包含键和键的所有值的列表。在一个空的字典上调用时将引发KeyError
>>> q = QueryDict('a=1&a=2&a=3', mutable=True)
>>> q.popitem()#('a', ['1', '2', '3'])
QueryDict.dict()将QueryDict转换为Python的字典数据类型,并返回该字典。
如果出现重复的键,则将所有的值打包成一个列表,最为新字典中键的值
>>> q = QueryDict('a=1&a=3&a=5')
>>> q.dict()#{'a': '5'}
QueryDict.urlencode(safe=None)[source]已url的编码格式返回数据字符串
>>> q = QueryDict('a=2&b=3&b=5')
>>> q.urlencode()#'a=2&b=3&b=5'
= = =
#HttpResponse
我们编写的每个视图都要实例化、填充和返回一个HttpResponse对象。也就是函数的return值。
>>> from django.http import HttpResponse
>>> response = HttpResponse("Here's the text of the Web page.")
>>> response = HttpResponse("Text only, please.", content_type="text/plain")
>>> response = HttpResponse()
>>> response.write("<p>Here's the text of the Web page.</p>")#可以write()不短写入内容
可以把HttpResponse对象当作一个字典一样,在其中增加和删除头部字段,与字典不同的是,如果要删除的头部字段如果不存在,del不会抛出KeyError异常
>>> response = HttpResponse()
>>> response['Age'] = 120
>>> del response['Age']
让浏览器以文件附件的形式处理响应, 需要声明content_type类型和设置Content-Disposition头信息
>>> response = HttpResponse(my_data, content_type='application/vnd.ms-excel')
>>> response['Content-Disposition'] = 'attachment; filename="foo.xls"'
HttpResponse.content
HttpResponse.charset
HttpResponse.status_code
HttpResponse.reason_phrase响应的HTTP原因短语
HttpResponse.streaming这个值总为False,能使得中间件能够区别对待流式响应和常规响应
HttpResponse.closed响应已关闭True/False
#方法
HttpResponse.init(content='', content_type=None, status=200, reason=None, charset=None)[source]
HttpResponse.has_header(header)检查头部中是否有给定的名称(不区分大小写),返回True或 False
HttpResponse.setdefault(header, value)设置一个头部,除非该头部已经设置过了
HttpResponse.set_cookie(key, value='', max_age=None, expires=None, path='/', domain=None, secure=None, httponly=False)
设置一个Cookie。 参数与Python标准库中的Morsel.Cookie对象相同
domain: 用于设置跨域的Cookie。例如domain=".lawrence.com"将设置一个www.lawrence.com、blogs.lawrence.com和calendars.lawrence.com都可读的Cookie。 否则,Cookie将只能被设置它的域读取。
阻止客服端的JavaScript访问Cookie,可以设置httponly=True
HttpResponse.set_signed_cookie(key, value, salt='', max_age=None, expires=None, path='/', domain=None, secure=None, httponly=True)
与set_cookie()类似,但是在设置之前将对cookie进行加密签名。通常与HttpRequest.get_signed_cookie()一起使用
HttpResponse.delete_cookie(key, path='/', domain=None)
删除Cookie中指定的key。
由于Cookie的工作方式,path和domain应该与set_cookie()中使用的值相同,否则Cookie不会删掉
HttpResponse.write(content)[source]将HttpResponse实例看作类似文件的对象,往里面添加内容
HttpResponse.flush()清空HttpResponse实例的内容
HttpResponse.tell()[source]将HttpResponse实例看作类似文件的对象,移动位置指针
HttpResponse.getvalue()[source]返回HttpResponse.content的值。 此方法将HttpResponse实例看作是一个类似流的对象
HttpResponse.readable()Django1.10中的新功能,值始终为False
HttpResponse.seekable()Django1.10中的新功能,值始终为False
HttpResponse.writable()[source]Django1.10中的新功能,值始终为True
HttpResponse.writelines(lines)[source]将一个包含行的列表写入响应对象中。 不添加分行符
#衍生子类
Django包含了一系列的HttpResponse衍生类(子类),用来处理不同类型的HTTP响应。与HttpResponse相同, 这些衍生类存在于django.http之中。
class HttpResponseRedirect[source]:重定向,返回302状态码。已经被redirect()替代。
class HttpResponsePermanentRedirect[source]:永久重定向,返回301状态码。
class HttpResponseNotModified[source]:未修改页面,返回304状态码。
class HttpResponseBadRequest[source]:错误的请求,返回400状态码。
class HttpResponseNotFound[source]:页面不存在,返回404状态码。
class HttpResponseForbidden[source]:禁止访问,返回403状态码。
class HttpResponseNotAllowed[source]:禁止访问,返回405状态码。
class HttpResponseGone[source]:过期,返回405状态码。
class HttpResponseServerError[source]:服务器错误,返回500状态码。
#JsonResponse
JsonResponse是HttpResponse的一个子类,是Django提供的用于创建JSON编码类型响应的快捷类,默认Content-Type头部设置为application/json
JsonResponse(data,encoder = DjangoJSONEncoder,safe = True,json_dumps_params = None ,** kwargs)[source]
>>> from django.http import JsonResponse
>>> response = JsonResponse({'foo': 'bar'})
>>> response.content#b'{"foo": "bar"}'
若要序列化非dict对象,必须设置safe参数为False,不传递safe=False,将抛出一个TypeError
>>> response = JsonResponse([1, 2, 3], safe=False)
如果你需要使用不同的JSON 编码器类,可以传递encoder参数给构造函数
>>> response = JsonResponse(data, encoder=MyJSONEncoder)
#StreamingHttpResponse
StreamingHttpResponse类被用来从Django响应一个流式对象到浏览器,对于生成大型的CSV文件非常有用
#FileResponse
FileResponse是StreamingHttpResponse的衍生类
>>> from django.http import FileResponse
>>> response = FileResponse(open('myfile.png', 'rb'))
= = =
文件上传打包在request.FILES
request.FILES只有在请求方法为POST,并且提交请求的<form>具有enctype="multipart/form-data"属性时才有效。 否则,request.FILES将为空。
# forms.py
from django import forms
class UploadFileForm(forms.Form):
title = forms.CharField(max_length=50)
file = forms.FileField()
用request.FILES['file']来获取上传文件的具体数据
# views.py
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import UploadFileForm
# 另外写一个处理上传过来的文件的方法,并在这里导入
from somewhere import handle_uploaded_file
def upload_file(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES) # 注意获取数据的方式必须将request.FILES传递到form的构造函数中。
if form.is_valid():
handle_uploaded_file(request.FILES['file'])
return HttpResponseRedirect('/success/url/')
else:
form = UploadFileForm()
return render(request, 'upload.html', {'form': form})
处理上传文件的方法
def handle_uploaded_file(f):
with open('some/file/name.txt', 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
遍历UploadedFile.chunks(),而不是直接使用read()方法,能确保大文件不会占用系统过多的内存
= = =
@使用模型层的model来指定上传文件的保存方式使用ModelForm更方便。
调用form.save()的时候,文件对象会保存在相应的FileField的upload_to参数指定的地方
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import ModelFormWithFileField
def upload_file(request):
if request.method == 'POST':
form = ModelFormWithFileField(request.POST, request.FILES)#使用模型
if form.is_valid():
# 这么做就可以了,文件会被保存到Model中upload_to参数指定的位置
form.save()#保存在相应的FileField的upload_to参数
return HttpResponseRedirect('/success/url/')
else:
form = ModelFormWithFileField()
return render(request, 'upload.html', {'form': form})
@如果手动构造一个对象,还可以简单地把文件对象直接从request.FILES赋值给模型
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import UploadFileForm
from .models import ModelWithFileField
def upload_file(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)#构造对象
if form.is_valid():
instance = ModelWithFileField(file_field=request.FILES['file'])#直接赋值给模型
instance.save()#保存在相应的FileField的upload_to参数
return HttpResponseRedirect('/success/url/')
else:
form = UploadFileForm()
return render(request, 'upload.html', {'form': form})
@如果要使用一个表单字段同时上传多个文件,需要设置字段HTML标签的multiple属性为True,如下所示:
# forms.py
from django import forms
class FileFieldForm(forms.Form):
file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
# views.py
from django.views.generic.edit import FormView
from .forms import FileFieldForm
class FileFieldView(FormView):
form_class = FileFieldForm
template_name = 'upload.html' # 用你的模版名替换.
success_url = '...' # 用你的URL或者reverse()替换.
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
files = request.FILES.getlist('file_field')
if form.is_valid():
for f in files:
... # Do something with each file.
return self.form_valid(form)
else:
return self.form_invalid(form)
@上传文件处理器
上传处理器的配置定义在FILE_UPLOAD_HANDLERS
["django.core.files.uploadhandler.MemoryFileUploadHandler", "django.core.files.uploadhandler.TemporaryFileUploadHandler"]
MemoryFileUploadHandler和TemporaryFileUploadHandler定义了Django的默认文件上传行为:将小文件读取到内存中,大文件放置在磁盘中
普通写入csv
import csv
from django.http import HttpResponse
def some_view(request):
# Create the HttpResponse object with the appropriate CSV header.
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="somefilename.csv"'
writer = csv.writer(response)
writer.writerow(['First row', 'Foo', 'Bar', 'Baz'])
writer.writerow(['Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"])
return response
#利用Python的生成器来有效处理大尺寸CSV文件的拼接和传输,Django的StreamingHttpResponse避免断连
import csv
from django.http import StreamingHttpResponse
class Echo(object):
"""An object that implements just the write method of the file-like
interface.
"""
def write(self, value):
"""Write the value by returning it, instead of storing in a buffer."""
return value
def some_streaming_csv_view(request):
"""A view that streams a large CSV file."""
# Generate a sequence of rows. The range is based on the maximum number of
# rows that can be handled by a single sheet in most spreadsheet
# applications.
rows = (["Row {}".format(idx), str(idx)] for idx in range(65536))
pseudo_buffer = Echo()
writer = csv.writer(pseudo_buffer)
response = StreamingHttpResponse((writer.writerow(row) for row in rows),
content_type="text/csv")
response['Content-Disposition'] = 'attachment; filename="somefilename.csv"'
return response
#使用Django的模板系统来生成CSV不建议使用=for
{% for row in data %}"{{ row.0|addslashes }}", "{{ row.1|addslashes }}", "{{ row.2|addslashes }}", "{{ row.3|addslashes }}", "{{ row.4|addslashes }}"
{% endfor %}
from django.http import HttpResponse
from django.template import loader, Context
def some_view(request):
# Create the HttpResponse object with the appropriate CSV header.
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="somefilename.csv"'
# The data is hard-coded here, but you could load it from a database or
# some other source.
csv_data = (
('First row', 'Foo', 'Bar', 'Baz'),
('Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"),
)
t = loader.get_template('my_template_name.txt')
c = Context({
'data': csv_data,
})
response.write(t.render(c))
return response
@动态生成PDF文件
不是线程安全的
pip install reportlab
from reportlab.pdfgen import canvas
from django.http import HttpResponse
def some_view(request):
# 创建带有PDF头部定义的HttpResponse对象
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"'
# 创建一个PDF对象,并使用响应对象作为它要处理的‘文件’
p = canvas.Canvas(response)
# 通过PDF对象的drawString方法,写入一条信息。具体参考模块的官方文档说明。
p.drawString(100, 100, "Hello world.")
# 关闭PDF对象
p.showPage()
p.save()
return response
#复杂的PDF涉及IO
from io import BytesIO
from reportlab.pdfgen import canvas
from django.http import HttpResponse
def some_view(request):
# Create the HttpResponse object with the appropriate PDF headers.
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"'
buffer = BytesIO()
# Create the PDF object, using the BytesIO object as its "file."
p = canvas.Canvas(buffer)
# Draw things on the PDF. Here's where the PDF generation happens.
# See the ReportLab documentation for the full list of functionality.
p.drawString(100, 100, "Hello world.")
# Close the PDF object cleanly.
p.showPage()
p.save()
# Get the value of the BytesIO buffer and write it to the response.
pdf = buffer.getvalue()
buffer.close()
response.write(pdf)
return response