视图函数简称视图,本质上是一个简单的python函数,它接受web请求而且返回web响应;响应的内容能够是HTML网页、重定向、404错误、XML文档或图像等任何东西,可是,不管视图自己是个什么处理逻辑,最好都返回某种响应html
视图函数的代码写在哪都无所谓,只要它在你的python目录下面,可是一般咱们约定将视图放置在项目或应用程序目录中的名为views.py的文件中。python
下面是一个返回当前日期和时间做为HTML文档的视图:程序员
from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html)
让咱们逐行分析一下上面的代码:web
首先,从django.http模块导入了HttpResponse类,以及python的datetime库ajax
接着,咱们定义了current_datetime视图函数django
每一个视图函数都接收一个HttpRequest对象做为第一位置参数,通常取名为request,你能够取别的名字,但这不符合潜规则,最好不要那么作json
视图函数的名称没有强制规则,但尽可能不要和python及django内置的各类名称重名,而且尽可能精确地反映出它的功能,好比这里的current_datetime跨域
该视图返回一个HttpResponse对象,其中包含生成的HTML页面。浏览器
在django中返回http错误代码是很是简单的;HttpResponse的许多子类对应着除了200(表明OK)之外的一些经常使用的http状态码。安全
为了标识一个错误,能够直接返回那些子类中的一个实例,而不是普通的HttpResponse,想下面这样:
from django.http import HttpResponse, HttpResponseNotFound def my_view(request): # ... if foo: return HttpResponseNotFound('<h1>Page not found</h1>') else: return HttpResponse('<h1>Page was found</h1>')
django为404错误提供了一个特化的子类HttpResponseNotFound;因为一些状态码不太经常使用,因此不是每一个状态码都有一个特化的子类。
也能够向HttpResponse的构造器传递HTTP状态码,来建立你想要的任何状态码的返回类,像下面这样:
from django.http import HttpResponse def my_view(request): # ... # Return a "created" (201) response code. return HttpResponse(status=201)
关键是在返回中提供status=201参数,别的什么303之类的错误均可以参照上面的例子。
class django.http.Http404
这是一个django内置的异常类,能够在须要的地方弹出它,django会捕获它,而且带上HTTP404错误码返回你当前APP的标准错误页面或者自定义错误页面,像下面这样:
from django.http import Http404 from django.shortcuts import render from polls.models import Poll def detail(request, poll_id): try: p = Poll.objects.get(pk=poll_id) except Poll.DoesNotExist: raise Http404("Poll does not exist") return render(request, 'polls/detail.html', {'poll': p})
为了在django返回404时显示自定义的HTML,能够建立要给名为404.html的HTML模版,并将其放置在模版树的顶层,当DEBUG设置为False时,此模版将被自动使用,当DEBUG为True时,能够向Http404提供消息,它将显示在标准的内置404调试模版中,可使用这些消息进行调试。
django在django.shortcuts模块中,为咱们提供了不少快捷方便的类和方法,它们都很重要,使用频率很高。
(1)render()
render(request,template_name,context=None,content_type=None,status=None,using=None)
结合一个给定的模版和一个给定的上下文字典,返回一个渲染后的HttpResponse对象。
必须参数:
可选参数:
示例:
下面的示例将渲染模版myapp/index.html,MIME类型为application/xhtml+xml:
from django.shortcuts import render def my_view(request): # View code here... return render(request, 'myapp/index.html', { 'foo': 'bar', }, content_type='application/xhtml+xml')
与下面的示例效果同样:
from django.http import HttpResponse from django.template import loader def my_view(request): # View code here... t = loader.get_template('myapp/index.html') c = {'foo': 'bar'} return HttpResponse(t.render(c, request), content_type='application/xhtml+xml')
(2)redirect()
redirect(to,permanent=False,args,*kwargs)
根据传递进来的URL参数,返回HttpResponseRedirect
参数to能够是:
默认状况下是临时重定向,若是设置permanent=True将永久重定向。
示例:
调用对象的get_absolute_url()方法来重定向URL:
from django.shortcuts import redirect def my_view(request): ... object = MyModel.objects.get(...) return redirect(object)
传递视图名,使用reverse()方法反向解析url:
def my_view(request): ... return redirect('some-view-name', foo='bar')
重定向到硬编码的URL:
def my_view(request): ... return redirect('/some/url/')
也适用于完整的URL:
def my_view(request): ... return redirect('https://example.com/')
全部上述形式都接受permanent参数,若是设置为true将返回永久重定向:
def my_view(request): ... object = MyModel.objects.get(...) return redirect(object, permanent=True)
(3)get_object_or_404()
get_object_or_404(klass,*args,**kwargs)
这个方法很是有用,经常使用于查询模型对象,找到则进行下一步处理,若是未找到则给用户返回404页面
在后台,django实际上是调用了模型管理器的get()方法,只是返回一个对象,不一样的是,若是get()发生异常,会引起Http404异常,从而返回404页面,而不是模型的DoesNotExist异常。
必需参数:
klass:要获取的对象的model类名或者QuerySet等
**kwargs:查询的参数,格式应该能够被get()接受
示例:
从MyModel中使用主键1来获取对象:
from django.shortcuts import get_object_or_404 def my_view(request): my_object = get_object_or_404(MyModel, pk=1)
上面的例子同下面同样:
from django.http import Http404 def my_view(request): try: my_object = MyModel.objects.get(pk=1) except MyModel.DoesNotExist: raise Http404("No MyModel matches the given query.")
除了传递model名称,还能够传递一个QuerySet实例:
queryset = Book.objects.filter(title__startswith='M') get_object_or_404(queryset, pk=1)
上面的示例不够简洁,由于它等同于:
get_object_or_404(Book, title__startswith='M', pk=1)
可是若是你的queryset来自其余地方,它就会颇有用了
还可使用manager,若是你自定义了管理器,这将颇有用:
get_object_or_404(Book.dahl_objects, title='Matilda')
还可使用related managers:
author = Author.objects.get(name='Roald Dahl') get_object_or_404(author.book_set, title='Matilda')
与get()同样,若是找到多个对象将引起一个MultipleObjectsReturned异常。
(4)get_list_or_404()
get_list_or_404(klass,*args,**kwargs)
这其实就是get_object_or_404多值获取版本;在后台,返回一个给定模型管理器上的filer()的结果,并将结果映射为一个列表,若是结果为空则弹出Http404异常
必需参数:
klass:获取该列表的一个model、manager或QuerySet实例
**kwargs:查询的参数,格式应该能够被filter()接受
示例:
下面的示例从mymodel中获取全部发布出来的对象:
from django.shortcuts import get_list_or_404 def my_view(request): my_objects = get_list_or_404(MyModel, published=True)
上面的例子同下面同样:
from django.http import Http404 def my_view(request): my_objects = list(MyModel.objects.filter(published=True)) if not my_objects: raise Http404("No MyModel matches the given query.")
每当一个用户请求发送过来,django将http数据包中的相关内容,打包成为一个HttpRequest对象,并传递给视图函数做为第一个位置参数,也就是reques,视图函数负责返回一个HttpResponse对象
HttpRequest和HttpResponse对象定义在django.http模块中
(1)属性
HttpRequest对象的大部分属性是只读的,除非特别注明
if request.method == 'GET': do_something() elif request.method == 'POST': do_something_else()
经过这个属性来判断请求的方法,而后根据请求的方法不一样,在视图中执行不一样的代码。
以上只是比较重要和经常使用的,还有不少未列出,从上面能够看到,除CONTENT_LENGTH和CONTENT_TYPE以外,请求中的任何HTTP头部键转换为META键时,都会将全部字母大写并将链接符替换为下划线最后加上HTTP_前缀,因此,一个叫作X-Bender的头部将转换成META中的HTTP_X_BENDER键。
{'Content-Length': '', 'Content-Type': 'text/plain', 'Host': '127.0.0.1:8000', 'Connection': 'keep-alive', 'Cache-Control': 'max-age=0', 'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Accept-Encoding': 'gzip, deflate, sdch, br', 'Accept-Language': 'zh-CN,zh;q=0.8', 'Cookie': 'sessionid=rff2y86kaa57vpsihwgo5j72v11c4m0i; csrftoken=tPHBVfuGzw4lYSNuaWYEXvJa2oiXlCEZeStm9LSLNfxRKxRY0p6xvYnr0518LN0L'}
(2)可自定义的属性
(3)由中间件设置的属性
django的contrib应用中包含的一些中间件会在请求上设置属性:
if request.user.is_authenticated: ... # Do something for logged-in users. else: ... # Do something for anonymous users.
(4)方法
根据HTTP_X_FORWARDED_HOST和HTTP_HOST头部信息获取请求的原始主机,若是这两个头部没有提供相应的值,则使用SERVER_NAME和SERVER_PORT,如:127.0.0.1:8000
注:当主机位于多个代理的后面,get_host()方法将会失败,解决办法之一是使用中间件重写代理的头部,以下示例:
from django.utils.deprecation import MiddlewareMixin class MultipleProxyMiddleware(MiddlewareMixin): FORWARDED_FOR_FIELDS = [ 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED_HOST', 'HTTP_X_FORWARDED_SERVER', ] def process_request(self, request): """ Rewrites the proxy headers so that only the most recent proxy is used. """ for field in self.FORWARDED_FOR_FIELDS: if field in request.META: if ',' in request.META[field]: parts = request.META[field].split(',') request.META[field] = parts[-1].strip()
例如:"https://example.com/music/bands/the_beatles/?print=true"
注:不鼓励在同一站点混合部署HTTP和HTTPS,若是须要将用户重定向到HTTPS,最好使用Web服务器将全部HTTP流量重定向到HTTPS。
可选参数salt用来为密码加盐,提升安全系数。 max_age参数用于检查Cookie对应的时间戳是否超时。
>>> request.get_signed_cookie('name') 'Tony' >>> request.get_signed_cookie('name', salt='name-salt') 'Tony' # assuming cookie was set using the same salt >>> request.get_signed_cookie('nonexistent-cookie') ... KeyError: 'nonexistent-cookie' >>> request.get_signed_cookie('nonexistent-cookie', False) False >>> request.get_signed_cookie('cookie-that-was-tampered-with') ... BadSignature: ... >>> request.get_signed_cookie('name', max_age=60) ... SignatureExpired: Signature age 1677.3839159 > 60 seconds >>> request.get_signed_cookie('name', False, max_age=60) False
HttpRequest.is_secure():若是使用的是Https,则返回True,表示链接是安全的。
HttpRequest.is_ajax():若是请求是经过XMLHttpRequest生成的,则返回True;这个方法的做用就是判断,当前请求是否经过ajax机制发送过来的。
HttpRequest.read(size=None)
HttpRequest.readline()
HttpRequest.readlines()
HttpRequest.xreadlines()
HttpRequest.iter()
上面的几个方法都是从HttpRequest实例读取文件数据的方法。
能够将HttpRequest实例直接传递到XML解析器,例如ElementTree:
import xml.etree.ElementTree as ET for element in ET.iterparse(request): process(element)
在HttpRequest对象中,GET和POST属性都是一个django.http.QueryDict的实例。也就是说你能够按本文下面提供的方法操做request.POST和request.GET。
request.POST或request.GET的QueryDict都是不可变,只读的。若是要修改它,须要使用QueryDict.copy()方法,获取它的一个拷贝,而后在这个拷贝上进行修改操做。
(1)方法
QueryDict 实现了Python字典数据类型的全部标准方法,由于它是字典的子类。
不一样之处在于下面:
QueryDict.init(query_string=None, mutable=False, encoding=None):QueryDict实例化方法。注意:QueryDict的键值是能够重复的
>>> QueryDict('a=1&a=2&c=3') <QueryDict: {'a': ['1', '2'], 'c': ['3']}>
若是须要实例化能够修改的对象,添加参数mutable=True
classmethod QueryDict.fromkeys(iterable, value='', mutable=False, encoding=None):
循环可迭代对象中的每一个元素做为键值,并赋予一样的值。
>>> QueryDict.fromkeys(['a', 'a', 'b'], value='val') <QueryDict: {'a': ['val', 'val'], 'b': ['val']}>
QueryDict.__getitem__():返回给定键的值,若是键具备多个值,则返回最后一个值
QueryDict.__setitem__(ke,value):将给定键设置为value,只能在可变的QueryDict上调用
QueryDict.__contains__():判断给定键是否存在
QueryDict.get(ke,default=None):同__getitem__()相同,只是多个了默认值返回
QueryDict.setdefault(key,default=None):它在__setitem__()内部使用
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'] # returns the last '2'
QueryDict.items():相似dict.items(),若是有重复项目,返回最近的一个:
>>> q = QueryDict('a=1&a=2&a=3') >>> list(q.items()) [('a', '3')]
QueryDict.values():相似dict.values(),可是只返回最近的值,以下:
>>> q = QueryDict('a=1&a=2&a=3') >>> list(q.values()) ['3']
QueryDict.copy():使用copy.deepcopy()返回QueryDict对象的副本,此副本是可变的
QueryDict.getlist(key,defautl=None):返回键对应的值的列表,若是该键不存在而且为提供默认值,则返回一个空列表
QueryDict.setlist(key,list_):为list_设置给定的键
QueryDict.appendlist(key,item):将键追加到内部与键相关联的列表中
QueryDict.setdefault(key,default=None):相似dict.setdefault(),为某个键设置默认值
QueryDict.lists():相似items(),只是它将其中的每一个键的值做为列表放在一块儿,以下:
>>> q = QueryDict('a=1&a=2&a=3') >>> q.lists() [('a', ['1', '2', '3'])]
QueryDict.pop(key):返回给定键的值的列表,并从QueryDict中移除该值,如键不存在则引起异常
>>> q = QueryDict('a=1&a=2&a=3', mutable=True) >>> q.pop('a') ['1', '2', '3']
QueryDict.popitem():删除QueryDict任意一个键,并返回二值元组,包含键和键的全部值的列表,在一个空的字典上调用时将引起KeyErro,以下:
>>> 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=Noen):为已编码的格式返回数据字符串:
>>> q = QueryDict('a=2&b=3&b=5') >>> q.urlencode() 'a=2&b=3&b=5'
使用该safe参数传递不须要编码的字符:
>>> q = QueryDict(mutable=True) >>> q['next'] = '/a&b/' >>> q.urlencode(safe='/') 'next=/a%26b/'
HttpResponse类定义在django.http模块中
HttpRequest对象由django自动建立,而HttpResponse对象则由程序员手动建立,咱们编写的每一个视图都要实例化、填充和返回一个HttpResponse对象,也就是函数的return值。
(1)使用方法
传递字符串:
最简单的方式his传递一个字符串做为页面的内容到HttpResponse构造函数,并返回给用户:
>>> 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(b'Bytestrings are also accepted.')
但,若是要增量添加内容,能够将其response用做类文件对象,使用write()方法不断往里增长内容:
>>> response = HttpResponse() >>> response.write("<p>Here's the text of the Web page.</p>") >>> response.write("<p>Here's another paragraph.</p>")
传递可迭代对象:
HttpResponse会当即处理迭代器,并把它的内容存成字符串,最后废弃这个迭代器,好比文件在读取后,会马上调用close()方法,关闭文件
设置头部字段:
能够把HttpResponse对象看成一个字典同样,在其中增长和删除头部字段:
>>> response = HttpResponse() >>> response['Age'] = 120 >>> del response['Age']
注意!与字典不一样的是,若是要删除的头部字段若是不存在,del不会抛出KeyError异常。
HTTP的头部字段中不能包含换行。因此若是咱们提供的头部字段值包含换行符(CR或者LF),将会抛出BadHeaderError异常
告诉浏览器将响应视为文件附件:
让浏览器以文件附件的形式处理响应,须要声明content_type类型和设置Content-Disposition头信息,给浏览器返回一个微软电子表格:
>>> response = HttpResponse(my_data, content_type='application/vnd.ms-excel') >>> response['Content-Disposition'] = 'attachment; filename="foo.xls"'
(2)属性
HttpResponse.content:响应的内容,bytes类型
HttpResponse.charset:编码的字符集,若是没指定,将会从content_type中解析出来
HttpResponse.status_code:响应的状态码,好比200
HttpResponse.reason_phrase:响应的HTTP缘由短语,使用标准缘由短语,除非明确设置,不然reason_phrase由status_code的值决定
HttpResponse.streaming:这个属性的值老是False,因为这个属性的存在,使得中间件可以区别对待流式响应和常规响应
HttpResponse.closed:若是响应已关闭,那么这个属性的值为True
(3)方法
HttpResponse.init(content='',content_type=None,status=200,reason=None,charset=None):响应的实例化方法,使用content参数和content_type实例化一个HttpResponse对象;content应该是一个迭代器或者字符串,若是是迭代器,这个迭代器返回的应是字符串,而且这些字符串链接起来造成response的内容,若是不是迭代器或者字符串,那么在其被接收的时候将转换成字符串。
content_type是可选的,用于填充HTTP的content_type头部,若是未指定,默认状况下由DEFAULT_CONTENT_TYPE和DEFAULT_CHARSET设置成:text/html;charset=utf-8
status是响应的状态码,resaon是HTTP响应短语,charset是编码方式
HttpResponse.has_header(header):检查头部中是否有给定的名称(不区分大小写),返回true或false
HttpResponse.__setitem__(header,value):设置标头
HttpResponse.__delitem__(header):删除标头
HttpResponse.__getitem__(header):查看标头
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对象相同;max_age为生存周期以秒为单位;expires为到期时间;domain用于设置跨域的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进行加密签名,一般与HttpResponse.get_signed_cookie()一块儿使用
HttpResponse.delete_cookie(key,path='/',domain=None):删除cookie中指定的key,因为cookie工做方式,path和domain应该与set_cookie()使用的值相同,不然cookie不会删除
HttpResponse.write(content):将HttpResponse实例看做相似文件的对象,往里添加内容
HttpResponse.flush():清空HttpResponse实例的内容
HttpResponse.tell():将HttpResponse实例看做相似文件的对象,移动位置指针
HttpResponse.getvalue():返回HttpResponse的值,此方法将HttpResponse实例看做是一个相似流的对象
HttpResponse.readable():此方法使HttpResponse实例成为相似流的对象,值始终为False
HttpResponse.seekable():此方法使HttpResponse实例成为相似流的对象,值始终为False
HttpResponse.writable():此方法使HttpResponse实例成为相似流的对象,值始终为True
HttpResponse.writelines(lines):将一个包含行的列表写入响应对象中,不添加分行符
(4)HttpResponse子类
Django包含许多HttpResponse衍生类(子类),用来处理不一样类型的HTTP响应,这些子类存在于django.http之中:
class HttpResponseRedirect:用来重定向,第一个参数必须是重定向到的路径,能够是彻底限定的URL,或没有域的绝对路径,或者是相对路径;它将返回状态码302
class HttpResponsePermanentRedirect:永久重定向,返回301状态码
class HttpResponseNotModified:未修改页面,返回304状态码
class HttpResponseBadRequest:错误的请求,返回400状态码
class HttpResponseNotFound:页面不存在,返回404状态码
class HttpResponseForbidden:禁止访问,返回403状态码
class HttpResponseNotAllowed:禁止访问,返回405状态码
class HttpResponseGone:过时,返回410状态码
class HttpResponseServerError:服务器错误,返回500状态码
(5)JsonResponse类
classJsonResponse(data,encoder = DjangoJSONEncoder,safe = True,json_dumps_params = None,**kwargs)
JsonResponse是HttpResponse的一个子类,是Django提供的用于建立JSON编码类型响应的快捷类
它从父类继承大部分行为,并具备如下不一样点:
它的默认Content-Type头部设置为application/json
它的第一个参数data,一般应该为一个字典数据类型,若是safe参数设置为False,则能够是任何可JSON序列化的对象
encoder默认为django.core.serializers.json.DjangoJSONEncoder,用于序列化数据
布尔类型参数safe默认为True,若是设置为False,能够传递任何对象进行序列化,不然只容许dict实例
典型的用法以下:
>>> 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)
(6)StreamingHttpResponse类
StreamingHttpResponse类被用来从Django响应一个流式对象到浏览器。若是生成的响应太长或者是占用的内存较大,这么作可能更有效率。 例如,它对于生成大型的CSV文件很是有用。
StreamingHttpResponse不是HttpResponse的衍生类(子类),由于它实现了彻底不一样的应用程序接口。可是,除了几个明显不一样的地方,二者几乎彻底相同:
它将被赋予一个迭代器,产生字符串做为内容
除非经过迭代响应对象自己,不然没法访问其内容,只有在将响应返回给客户端时才会发生这种状况
它没有content属性,相反,它有一个streaming_content属性
你不能使用类文件对象tell()或write()方法
(7)FileResponse类
class FileResponse(open_file,as_attachment = False,filename='',**kwargs)
文件类型响应,一般用于给浏览器返回一个文件附件,FileResponse是StreamingHttpResponse的衍生类,为二进制文件专门作了优化
若是as_attachment=True,则要求浏览器将文件做为下载提供给用户
若是open_file没有名称或名称open_file不合适,请使用filename参数提供自定义文件名
FileResponse接受任何具备二进制内容的类文件对象,以下以二进制模式打开文件:
>>> from django.http import FileResponse >>> response = FileResponse(open('myfile.png', 'rb'))
上面的文件将自动关闭,所以不要使用上下文管理器打开它
FileResponse.set_headers方法,在2.1中添加的新功能,它在初始化期间自动调用和设置不一样的报头(Content-Length,Content-Type和Content-Disposition),使用哪一种报头取决于打开的文件。
-------------------------------------------------------------------------------------------------------------------