django视图
django视图
限制请求method
Django内置的视图装饰器可以给视图提供一些限制。比如这个视图只能通过GET的method访问等。
以下将介绍一些常用的内置视图装饰器。
- django.http.decorators.http.require_http_methods:这个装饰器需要传递一个允许访问的方法的列表。比如只能通过GET的方式访问。那么示例代码如下:
from django.views.decorators.http import require_http_methods
@require_http_methods(["GET"])
def my_view(request):
pass
- django.views.decorators.http.require_GET:这个装饰器相当于是require_http_methods([‘GET’])的简写形式,只允许使用GET的method来访问视图。示例代码如下:
from django.views.decorators.http import require_GET
@require_GET
def my_view(request):
pass
- django.views.decorators.http.require_POST:这个装饰器相当于是require_http_methods([‘POST’])的简写形式,只允许使用POST的method来访问视图。示例代码如下:
from django.views.decorators.http import require_POST
@require_POST
def my_view(request):
pass
- django.views.decorators.http.require_safe:这个装饰器相当于是require_http_methods([‘GET’,‘HEAD’])的简写形式,只允许使用相对安全的方式来访问视图。因为GET和HEAD不会对服务器产生增删改的行为。因此是一种相对安全的请求方式。示例代码如下:
from django.views.decorators.http import require_safe
@require_safe
def my_view(request):
pass
重定向
重定向分为永久性重定向和暂时性重定向,在页面上体现的操作就是浏览器会从一个页面自动跳转到另外一个页面。比如用户访问了一个需要权限的页面,但是该用户当前并没有登录,因此我们应该给他重定向到登录页面。
永久性重定向
http的状态码是301,多用于旧网址被废弃了要转到一个新的网址确保用户的访问,最经典的就是京东网站,你输入www.jingdong.com的时候,会被重定向到www.jd.com,因为jingdong.com这个网址已经被废弃了,被改成jd.com,所以这种情况下应该用永久重定向。
暂时性重定向
http的状态码是302,表示页面的暂时性跳转。比如访问一个需要权限的网址,如果当前用户没有登录,应该重定向到登录页面,这种情况下,应该用暂时性重定向。
django中的重定向
使用redirect(to, *args, permanent=False, **kwargs)来实现的。to是一个url,permanent代表的是这个重定向是否是一个永久的重定向,默认是False。
from django.shortcuts import reverse,redirect
def profile(request):
if request.GET.get("username"):
return HttpResponse("%s,欢迎来到个人中心页面!")
else:
return redirect(reverse("user:login"))
WSGIRequest对象
django在接收到http请求之后,会根据http请求携带的参数以及报文信息创建一个WSGIRequest对象,并且作为视图函数第一个参数传给视图函数。也就是我们经常看到的request参数。在这个对象上我们可以找到客户端上传上来的所有信息。这个对象的完整路径是django.core.handlers.wsgi.WSGIRequest。
WSGIRequest对象常用属性和方法
WSGIRequest对象常用属性
WSGIRequest对象上大部分的属性都是只读的。因为这些属性是从客户端上传上来的,没必要做任何的修改。以下将对一些常用的属性进行讲解:
-
path:请求服务器的完整“路径”,但不包含域名和参数。比如http://www.baidu.com/xxx/yyy/,那么path就是/xxx/yyy/。
-
method:代表当前请求的http方法。比如是GET还是POST。
-
GET:一个django.http.request.QueryDict对象。操作起来类似于字典。这个属性中包含了所有以?xxx=xxx的方式上传上来的参数。
-
POST:也是一个django.http.request.QueryDict对象。这个属性中包含了所有以POST方式上传上来的参数。
-
FILES:也是一个django.http.request.QueryDict对象。这个属性中包含了所有上传的文件。
-
COOKIES:一个标准的Python字典,包含所有的cookie,键值对都是字符串类型。
-
session:一个类似于字典的对象。用来操作服务器的session。
-
META:存储的客户端发送上来的所有header信息。
CONTENT_LENGTH:请求的正文的长度(是一个字符串)。
CONTENT_TYPE:请求的正文的MIME类型。
HTTP_ACCEPT:响应可接收的Content-Type。
HTTP_ACCEPT_ENCODING:响应可接收的编码。
HTTP_ACCEPT_LANGUAGE: 响应可接收的语言。
HTTP_HOST:客户端发送的HOST值。
HTTP_REFERER:在访问这个页面上一个页面的url。
QUERY_STRING:单个字符串形式的查询字符串(未解析过的形式)。
REMOTE_ADDR:客户端的IP地址。如果服务器使用了nginx做反向代理或者负载均衡,那么这个值返回的是127.0.0.1,这时候可以使用HTTP_X_FORWARDED_FOR来获取,所以获取ip地址的代码片段如下:
if request.META.has_key('HTTP_X_FORWARDED_FOR'):
ip = request.META['HTTP_X_FORWARDED_FOR']
else:
ip = request.META['REMOTE_ADDR']
REMOTE_HOST:客户端的主机名。
REQUEST_METHOD:请求方法。一个字符串类似于GET或者POST。
SERVER_NAME:服务器域名。
SERVER_PORT:服务器端口号,是一个字符串类型。
QueryDict对象
request.GET和request.POST都是QueryDict对象,这个对象继承自dict,因此用法跟dict相差无几。其中用得比较多的是get方法和getlist方法。
get方法:用来获取指定key的值,如果没有这个key,那么会返回None。
getlist方法:如果浏览器上传上来的key对应的值有多个,那么就需要通过这个方法获取。
在restful API中,更多的是使用 json.loads(request.body)获取字典格式的数据:
HttpResponse对象
Django服务器接收到客户端发送过来的请求后,会将提交上来的这些数据封装成一个HttpRequest对象传给视图函数。
那么视图函数在处理完相关的逻辑后,必须返回HttpResponseBase或者他的子类的对象。而HttpResponse则是HttpResponseBase用得最多的子类。
HttpResponse常用属性:
- content:返回的内容。
- status_code:返回的HTTP响应状态码。
- content_type:返回的数据的MIME类型,默认为text/html。浏览器会根据这个属性,来显示数据。如果是text/html,那么就会解析这个字符串,如果text/plain,那么就会显示一个纯文本。常用的Content-Type如下:
text/html(默认的,html文件)
text/plain(纯文本)
text/css(css文件)
text/javascript(js文件)
multipart/form-data(文件提交)
application/json(json传输)
application/xml(xml文件) - 设置请求头:response[‘X-Access-Token’] = ‘xxxx’。
常用方法
- set_cookie:用来设置cookie信息。后面讲到授权的时候会着重讲到。
- delete_cookie:用来删除cookie信息。
- write:HttpResponse是一个类似于文件的对象,可以用来写入数据到数据体(content)中。
JsonResponse
用来对象dump成json字符串,然后返回将json字符串封装成Response对象返回给浏览器。并且他的Content-Type是application/json。示例代码如下:
from django.http import JsonResponse
def index(request):
return JsonResponse({"username":"zhiliao","age":18})
默认情况下JsonResponse只能对字典进行dump,如果想要对非字典的数据进行dump,那么需要给JsonResponse传递一个safe=False参数。示例代码如下:
from django.http import JsonResponse
def index(request):
persons = ['张三','李四','王五']
return JsonResponse(persons)
以上代码会报错,应该在使用HttpResponse的时候,传入一个safe=False参数,示例代码如下:
return JsonResponse(persons, safe=False)
生成CSV文件
生成小的CSV文件
- 初始化HttpResponse时,指定Content-Type为text/csv,这将告诉浏览器,这是一个csv格式的文件。
- 在response中添加一个Content-Disposition头,用来告诉浏览器该如何处理这个文件。这个头的值设置为attachment;,那么浏览器将不会对这个文件进行显示,而是作为附件的形式下载,第二个filename="somefilename.csv"是用来指定这个csv文件的名字。
- 使用csv模块的writer方法,将相应的数据写入到response中(HttpResponse实现了write方法所以可以像写文件使用一样csv写入数据)。
生成大的CSV文件
如果想要生成大型的csv文件,那么以上方式将有可能会发生超时的情况(服务器要生成一个大型csv文件,需要的时间可能会超过浏览器默认的超时时间)。这时候我们可以借助另外一个类,叫做StreamingHttpResponse对象,这个对象是将响应的数据作为一个流返回给客户端,而不是作为一个整体返回。
关于StreamingHttpResponse:
这个类是专门用来处理流数据的。使得在处理一些大型文件的时候,不会因为服务器处理时间过长而到时连接超时。这个类不是继承自HttpResponse,并且跟HttpResponse对比有以下几点区别:
- 这个类没有属性content,相反是streaming_content。
- 这个类的streaming_content必须是一个可以迭代的对象。
- 这个类没有write方法,如果给这个类的对象写入数据将会报错。
注意:StreamingHttpResponse会启动一个进程来和客户端保持长连接,所以会很消耗资源。所以如果不是特殊要求,尽量少用这种方法。
类视图
View
django.views.generic.base.View是主要的类视图,所有的类视图都是继承自他,自定义的类视图,也可以继承自它。
然后根据当前请求的method,来实现不同的方法。比如这个视图只能使用get的方式来请求,那么就可以在这个类中定义get(self,request,*args,**kwargs)方法。如果只需要实现post方法,那么就只需要在类中实现post(self,request,*args,**kwargs)。
示例代码如下:
注意: 映射的时候就需要调用View的类方法as_view()来进行转换。
未定义方法的处理
View支持方法: ‘get’、‘post’、‘put’、‘patch’、‘delete’、‘head’、‘options’、‘trace’。
如果用户访问了View中没有定义的方法。比如你的类视图只支持get方法,而出现了post方法,默认情况下是会返回405的状态码:
如果需要自定义处理这种情况,那么可以在类视图中自定义**http_method_not_allowed(request,*args,**kwargs)**方法:
根据method分发请求
类视图中,任何请求都会走dispatch(request,*args,**kwargs)方法做不同的请求分发:
TemplateView(前后端不分离才会用到)
django.views.generic.base.TemplateView,这个类视图是专门用来返回模版的。
ListView(前后端不分离才会用到)
在网站开发中,经常会出现需要列出某个表中的一些数据作为列表展示出来。比如文章列表,图书列表等等。在Django中可以使用ListView来帮我们快速实现这种需求。
分页
Django已经内置了两个处理分类的类,分别是Paginator和Page。Paginator用来管理整个分类的一些属性,Page用来管理当前这个分页的一些属性。
Paginator类
Paginator是用来控制整个分页的逻辑的,比如总共有多少页,页码区间等等。
创建Paginator对象:
class Paginator(object_list, per_page, orphans=0, allow_empty_first_page=True),其中的参数解释如下:
object_list:列表,元组,QuerySet或者是任何可以做切片操作的对象。会将这个里面的对象进行分页。
per_page:分页中,一页展示多少条数据。
orphans:用来控制最后一页元素的个人如果少于orphans指定的个数的时候,就会将多余的添加到上一页中。
allow_empty_first_page:如果object_list没有任何数据,并且这个参数设置为True,那么就会抛出EmptyPage异常。
常用属性和方法
- Paginator.page(number):获取number这页的Page对象。
- count:传进来的object_list总共的数量。
- num_pages:总共的页数。
- page_range:页码的列表。比如[1,2,3,4]。
Page类
has_next():是否还有下一页。
has_previous():是否还有上一页。
next_page_number():下一页的页码。
previous_page_number():上一页的页码。
number:当前页。
start_index:当前这一页的第一条数据的索引值。
end_index:当前这一页的最后一条数据的索引值。
object_list:在当前这页上的对象列表。
paginator:获取Paginator对象。
分页的基本使用
如下:
- Course.objects.all().order_by(“id”) 获取所有的Course对象。(这里还不会查数据库)
- Paginator的第一个参数需要传入一个可迭代对象,第二个参数是每页的个数。
- paginator.page(页数):返回当前页的Page对象,可以调用Page对象的一些方法和属性。这里会查询数据库获取Course的总数。
- 具体获取course对象的属性,比如id和name时才会去数据库查询course。
给类视图添加装饰器
如果想要给类添加装饰器,那么可以通过以下两种方式来实现。
装饰dispatch方法
dispatch方法中会分发请求,所以可以每个请求都会经过dipatch方法,可以在dispatch方法添加装饰器。
直接装饰在整个类上
cookie和session
cookie
Http请求是无状态的,也就是说即使第一次和服务器连接后并且登录成功后,第二次请求服务器依然不能知道当前请求是哪个用户。
cookie的出现就是为了解决这个问题,第一次登录后服务器返回一些数据(cookie)给浏览器,然后浏览器保存在本地,当该用户发送第二次请求的时候,就会自动的把上次请求存储的cookie数据自动的携带给服务器,服务器通过浏览器携带的数据就能判断当前是哪个用户了。
cookie存储的数据量有限,不同的浏览器有不同的存储大小,但一般不超过4KB。因此使用cookie只能存储一些小量的数据。
session
session和cookie的作用有点类似,都是为了存储用户相关的信息。不同的是,cookie是存储在本地浏览器,session是一个概念、一个服务器存储授权信息的解决方案,不同的服务器,不同的框架,不同的语言有不同的实现。虽然实现不一样,但是他们的目的都是服务器为了方便存储数据的。
session的出现,是为了解决cookie存储数据不安全的问题的。
cookie和session使用
web开发发展至今,cookie和session的使用已经出现了一些非常成熟的方案。
一般有两种存储方式:
-
存储在服务端:通过cookie存储一个sessionid,然后具体的数据则是保存在session中。如果用户已经登录,则服务器会在cookie中保存一个sessionid,下次再次请求的时候,会把该sessionid携带上来,服务器根据sessionid在session库中获取用户的session数据。就能知道该用户到底是谁,以及之前保存的一些状态信息。这种专业术语叫做server side session。
Django把session信息默认存储到数据库中,当然也可以存储到其他地方,比如缓存中,文件系统中等。存储在服务器的数据会更加的安全,不容易被窃取。但存储在服务器也有一定的弊端,就是会占用服务器的资源,但现在服务器已经发展至今,一些session信息还是绰绰有余的。 -
存储在客户端:将session数据加密,然后存储在cookie中。这种专业术语叫做client side session。Flask框架默认采用的就是这种方式,但是也可以替换成其他形式。
Django中操作cookie
cookie是设置给浏览器的,所以要通过response对象的set_cookie方法设置,然后将response对象返回给浏览器。
set_cookie方法
key:这个cookie的key。
value:这个cookie的value。
max_age:cookie的生命周期,单位是秒,过期浏览器会自动清理。
expires:过期时间。跟max_age是类似的,只不过这个参数需要传递一个具体的日期,比如datetime或者是符合日期格式的字符串。如果同时设置了expires和max_age,那么将会使用expires的值作为过期时间。
path:对域名下哪个路径有效。默认是对域名下所有路径都有效。
domain:针对哪个域名有效。默认是针对主域名下都有效,如果只要针对某个子域名才有效,那么可以设置这个属性。
secure:是否是安全的,如果设置为True,那么只能在https协议下才可用,也就是说cookie只能用https协议发送给服务器,用http协议是不发送的。
httponly:默认是False。如果为True,那么在客户端不能通过JavaScript进行操作,也就是说无法用document.cookie打出cookie的内容。
设置cookie
获取浏览器发送给服务器的cookie
设置httponly=True
设置secure=True
采用http访问服务器,浏览器接收到response中设置了cookie,但是实际浏览器并没有把这个cookie保存下来,下次请求也就不会带着cookie。
Django中操作session
session是存放在服务端的,在django中使用session必须要先在数据库中创建django_session表,session相关信息都要依赖此表。
-
通过request.session设置session:
-
session数据默认会保存在数据库的django_session表中,session_key为随机生成的
-
django会设置cookie,key为sessionid,value为session_key值(即数据库中的session_key):
-
获取浏览器通过cookie传入的session信息:
request.session会根据传入的cookie信息中的session_id去数据库中获取对应的session_value。
session常用的方法
获取session
request.session[‘status’]
**request.session.get(‘status’) ** #一般用get,无此键返回None不报错
设置session
**request.session[‘status’]=True ** # 存在自动覆盖
request.session.setdefault(‘k1’, 123) # 存在则不设置
删除session
**request.session.flush() ** # 删除服务端的session,删除当前的会话数据并删除会话的Cookie,一般退出登录时使用。
request.session.clear_expired() # 将所有Session失效日期小于当前日期的数据删除,将过期的删除。Django并不会清除过期的session,需要定期手动的清理,或者是在终端,使用命令行python manage.py clearsessions来清除过期的session。
**del request.session[‘k1’] ** # django-session表里面同步删除
request.session.delete() # 删除当前会话的Session数据,会把数据库中的数据也删除。
request.session.pop(session_key) # 从session中删除一个值,会把数据库中的session_id对应的value置为空,但是整条数据还在。
所有 键、值、键值对
request.session.keys()
request.session.values()
request.session.items()
获取sessionid的值
**session_key = request.session.session_key **
检查会话session的key在数据库中是否存在
request.session.exists(“session_key”) # session_key就是那个sessionid的值
设置会话Session和Cookie的超时时间
request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。
修改session的存储机制
默认情况下,session数据是存储到数据库中的。
可以通过设置SESSION_ENGINE来更改session的存储位置,这个可以配置为以下几种方案:
数据库存储
django.contrib.sessions.backends.db:使用数据库。默认就是这种方案。
文件存储
django.contrib.sessions.backends.file:使用文件来存储session。
SESSION_ENGINE = ‘django.contrib.sessions.backends.file’ # 引擎
SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()
缓存存储
django.contrib.sessions.backends.cache:使用缓存来存储session。
SESSION_ENGINE = ‘django.contrib.sessions.backends.cache’ # 引擎
SESSION_CACHE_ALIAS = ‘default’ # 使用的缓存别名(默认内存缓存,也可以是memcache、redis),此处别名依赖缓存的设置
使用redie缓存:link
数据库+缓存存储
django.contrib.sessions.backends.cached_db:在存储数据的时候,会将数据先存到缓存中,再存到数据库中。这样就可以保证万一缓存系统出现问题,session数据也不会丢失。在获取数据的时候,会先从缓存中获取,如果缓存中没有,那么就会从数据库中获取。
客户端浏览器cookie加密存储
django.contrib.sessions.backends.signed_cookies:将session信息加密后存储到浏览器的cookie中。这种方式要注意安全,建议设置SESSION_COOKIE_HTTPONLY=True,那么在浏览器中不能通过js来操作session数据,并且还需要对settings.py中的SECRET_KEY进行保密,因为一旦别人知道这个SECRET_KEY,那么就可以进行解密。另外还有就是在cookie中,存储的数据不能超过4k。
其他公用设置项:
SESSION_COOKIE_NAME = “sessionid” # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
SESSION_COOKIE_PATH = “/” # Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认)
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)