Django View视图
视图view
一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应。响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片。
无论视图本身包含什么逻辑,都要返回响应。大家约定成俗将视图放置在项目(project)或应用程序(app)目录中的名为views.py的文件中。
- Django使用请求Request和响应Response来给整个系统传递状态
- 当用户请求一个页面时,Django创建一个包含元数据和请求内容的HttpRequest对象。然后Django加载适当的视图,HttpRequest对象作为视图函数的第一个参数,每个视图负责返回一个HttpResponse对象。
from django.http import HttpResponse def show(req): name = 'Jerry' content = '<h1>hello %s!</h1>' % name return HttpResponse(content)
首先从 django.http模块导入了HttpResponse类。然后定义了show函数。它就是视图函数;每个视图函数的第一个参数都为request,其实是一个HttpRequest对象。视图函数中封装了一个HTML格式的字符串,传入HttpResponse()后,实例化一个HttpResponse对象并返回。
当浏览器向服务端请求一个页面时,Django创建一个HttpRequest对象,该对象包含关于请求的元数据。然后,Django加载相应的视图,将这个HttpRequest对象作为第一个参数传递给视图函数。
HttpRequest对象
对象属性
HttpRequest.scheme:字符串(http/https)表示http还是https请求
HttpRequest.body:原始的http请求主体
HttpRequest.path:完整的请求路径,不包括域
HttpRequest.method:请求中使用的HTTP方法(GET/POST)
HttpRequest.encoding:请求的字符集
HttpRequest.GET:类似字典的对象,包含所有给定的HTTP GET参数
HttpRequest.POST:类似字典的对象,包含所有给定的HTTP POST参数,前提是请求包含表单数据。
HttpRequest.COOKIES:客户端cookies信息,字典类型
HttpRequest.FILES:一个包含所有文件对象的字典. key是<inputtype="file" name="" />中name的值,每一个value是一个上传的文件对象,如果要上传文件需要在 <form> 标签中添加 enctype="multipart/form-data",不然收到的是一个空值
HttpRequest.META:请求的META属性
HttpRequest.headers:一个不区分大小写的类似dict的对象,包含请求中所有HTTP加前缀的标题的访问
def index(request): print(request.scheme) #http print(request.body) #b'' print(request.path) #/app/ print(request.method) #GET print(request.encoding) #None print(request.GET) #<QueryDict: {'name': ['aaa']}> print(request.POST) #<QueryDict: {}> print(request.META.get('CONTENT_TYPE')) #text/plain print(request.META.get('REMOTE_ADDR')) #127.0.0.1 print(request.headers.get('Connection')) #keep-alive print(request.headers.get('Accept-Encoding')) #gzip, deflate, br return HttpResponse('<h1>hello</h1>')
对象方法
HttpRequest.get_host():返回当前服务器的IP和端口
HttpRequest.get_port():返回当前服务器原始端口
HttpRequest.get_full_path():返回附加查询的请求路径
HttpRequest.is_secure():如果返回True,请求时安全的,也就是https协议
HttpRequest.is_ajax():是否为ajax请求
def index(request): print(request.get_host()) #127.0.0.1:8000 print(request.get_port()) #8000 print(request.get_full_path()) #/app/?name=aaa print(request.is_secure()) #False print(request.is_ajax()) #False return HttpResponse('<h1>hello</h1>')
HttpResponse对象
对象属性
HttpResponse.content:表示内容的字节字符串,如果需要,从字符串编码。
HttpResponse.charset:一个字符串,表示将在其中编码响应的字符集。如果未在HttpResponse实例化时间给出,则将从中提取 content_type,如果不成功,DEFAULT_CHARSET则将使用该 设置。
HttpResponse.status_code:该响应的HTTP状态代码。除非reason_phrase明确设置,否则修改 status_code构造函数外部的值也会修改值reason_phrase。
HttpResponse.reason_phrase:响应的HTTP原因短语。它使用了HTTP标准的默认原因短语。除非明确设置,否则reason_phrase由status_code的值确定。
对象方法
HttpResponse.__init__(content = b'', content_type=None, status=200, reason=None, charset=None)
使用给定的页面内容和内容类型实例化对象。
- content:最常见的是迭代器,字节串或字符串。其他类型将通过编码其字符串表示形式转换为bytestring。
- content_type:是可选的字符集编码完成的MIME类型,用于填充HTTP Content-Type标头。
- status:响应的HTTP状态代码。
- reason:HTTP响应短语。如果未提供,将使用默认短语。
- charset:编码响应的字符集。如果没有给出,它将从中提取content_type,如果不成功,DEFAULT_CHARSET将使用该设置。
HttpResponse.set_cookie(key, value, max_age=None, expires=None, path='/', domain=None, secure=None, httponly=False, samesite=None):设置一个cookie。
HttpResponse.set_signed_cookie(key, value, salt='', max_age=None, expires=None, path='/', domain=None, secure=None, httponly=False, samesite=None):在对cookie设置之前进行签名加密,加密后的cookie中的键值对将是密文的;获取cookie信息时也要使用相对应方法HttpRequest.get_signed_cookie()。
HttpResponse.delete_cookie(key,path ='/',domain = None):使用给定的key删除对应的cookie,path、domain应该指定和set_cookie()时相同的值。
render()
结合一个给定的模板和一个给定的上下文字典, 并返回一个渲染后的HttpResponse对象。
def render(request, template_name, context=None, content_type=None, status=None, using=None): """ Return a HttpResponse whose content is filled with the result of calling django.template.loader.render_to_string() with the passed arguments. """ content = loader.render_to_string(template_name, context, request, using=using) return HttpResponse(content, content_type, status)
必需参数:
- request:用于生成此响应的HttpRequest对象;
- template_name:要使用的模板的完整名称;
可选参数:
- context:添加到模板上下文的一个字典,默认是一个空字典, 通过它可以向模板传入自定义参数,视图将在渲染模板之前调用它;
- content_type:生成的文档要使用的MIME类型.,默认为DEFAULT_CONTENT_TYPE设置的值"text/html";
- status:响应的状态码. 默认为200;
- useing:用于加载模板的模板引擎的名称。
from django.shortcuts import render def my_view(request): active = True return render(request, 'index.html', {'name': active}, content_type='application/xhtml+xml')
redirect()
默认返回一个临时的重定向,传递permanent=True可以返回一个永久的重定向。临时重定向(响应状态码: 302)和永久重定向(响应状态码: 301)对普通用户来说是没什么区别的, 它主要面向的是搜索引擎的机器人。
def redirect(to, *args, permanent=False, **kwargs): """ Return an HttpResponseRedirect to the appropriate URL for the arguments passed. """ redirect_class = HttpResponsePermanentRedirect if permanent else HttpResponseRedirect return redirect_class(resolve_url(to, *args, **kwargs))
参数可以是:
- 一个模型: 将调用模型的get_absolute_url()函数
- 一个视图, 可以带有函数: 可以使用urlresolvers.reverse来反向解析名称
- 一个绝对的或相对的URL, 将原封不动的作为重定向的位置
from django.shortcuts import redirect def my_view(request): return redirect('/some/url/') def my_view(request): return redirect('https://example.com/')
Cookie、Session
浏览器请求服务器是无状态的。无状态指一次用户请求时,浏览器、服务器无法知道之前这个用户做过什么,每次请求都是一次新的请求。无状态的应用层面的原因是:浏览器和服务器之间的通信都遵守HTTP协议。根本原因是:浏览器与服务器是使用Socket套接字进行通信的,服务器将请求结果返回给浏览器之后,会关闭当前的Socket连接,而且服务器也会在处理页面完毕之后销毁页面对象。
但有时候用户需要保持登陆状态,或者一些。 实现会话保持主要有两种方式:cookie和session。
Cookie
Cookie是由服务器端生成,发送给User-Agent(一般是浏览器),浏览器会将Cookie的key/value保存到某个目录下的文本文件内,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)。通常情况下,它用于判断两个请求是否来自同一个浏览器 - 例如,保持用户登录。它记住无状态HTTP协议的有状态信息。
Cookie主要用于三个目的:
- 会话管理,登录,购物车,游戏分数或服务器应记住的任何其他内容;
- 个性化,用户首选项,主题和其他设置;
- 跟踪,记录和分析用户行为。
特点
cookie数据保存在客户端,以key-value存储;
cookie有过期时间,默认关闭浏览器过期;
cookie是基于域名安全的;
当浏览器请求某网站时,会将本网站下所有Cookie信息提交给服务器。
Session
session是存储在后端数据库中的键值对,django生成一个随机字符串sessionid作为key,用户的信息作为value;
当浏览器第一次发送请求时,服务器会生成与用户相关的session,然后将在sessionid放入cookie中返回给浏览器,浏览器会将此cookie保存在本地;之后每次请求时浏览器都会将这个cookie发给服务器,服务器在提取到sessionid后,会根据这个随机字符串去数据库中找出这个请求者的信息。
特点
session数据保存在服务器,以key-value存储;
session依赖于cookie,每个客户端的session信息标识保存在客户端cookie中;
session也有过期时间,django中session过期时间默认2周,flask开启session过期时间之后默认30天;
在视图中使用cookie
HttpResponse.set_cookie(key, value, max_age=None, expires=None, path='/', domain=None, secure=None, httponly=False, samesite=None)
设置一个cookie
- key、value:设置cookie中的键值,都是字符串类型;
- max_age:一个整数,表示在指定秒数后过期;
- expires:一个datetime或timedelta对象,会话将在这个指定的日期/时间过期;可以不设置,django会根据max_age自动设置;
- path:指定一个路径,只有在这个路径下才可以访问到cookie;
- domain:如果你想设置一个跨域的cookie。例如, domain="example.com"将设置域www.example.com,blog.example.com等可读的cookie。否则,cookie只能由设置它的域读取;
- Secure:https协议访问;
- httponly:如果为True,就阻止客户端的JavaScript操作cookie。
def login(request): re = redirect('/app/index.html') #实例一个redirect HttpResponse对象 re.set_cookie('username', username, max_age=20) #为对象设置cookie信息 return re #返回HttpResponse对象)
HttpResponse.set_signed_cookie(key, value, salt='', max_age=None, expires=None, path='/', domain=None, secure=None, httponly=False, samesite=None):在对cookie设置之前进行签名加密,加密后的cookie中的键值对将是密文的;获取cookie信息时也要使用相对应方法HttpRequest.get_signed_cookie();
HttpRequest.COOKIES.get(key, None):通过请求对象的COOKIES属性获取;
HttpRequest.get_signed_cookie(key):获取加密cookie的方法;
HttpResponse.delete_cookie(key,path ='/',domain = None):使用给定的key删除对应的cookie,path、domain应该指定和set_cookie()时相同的值。
在视图中使用session
当SessionMiddleware激活时,每个HttpRequest 对象 - 任何Django视图函数的第一个参数,将具有一个 session属性,这是一个类似字典的对象。request.session可以在视图中的任何位置查看编辑它。
backends.base.SessionBase类是所有的session对象的基类;它具有标准的字典方法;
# 设置session request.session[key] = value request.session.setdefault(key, value) # 修改session request.session[key] = value # 将新的字典更新进去 request.session.update(dicts) # 获取session request.session.get(key) request.session.keys() request.session.values() request.session.items() # 设置过期时间 request.session.set_expiry() # 获取过期时间、日期 request.session.get_expiry_age() request.session.get_expiry_date() # 是否关闭浏览器时session过期 request.session.get_expire_at_browser_close() # 从数据库存储中删除过期的会话 request.session.clear_expired() # 删除指定key del request.session[key] request.session.pop(key) # 清空session,不会删除数据库 request.session.clear() # 删除session_key的session数据,删除数据库 request.session.delete(session_key=None) request.session.flush() # 创建一个key唯一的新的session对象,并保存 request.session.create() # 保存session数据,如果must_create = True则创建新session request.session.save(must_create=False) # 创建新的session_key,同时保留当前session数据 request.session.cycle_key() # 加载session,返回一个字典 request.session.load() # 如果session为空,返回True request.session.is_empty() # 如果session_key已存在,则返回True request.session.exists(session_key) # 包含sessionid的属性 request.session.session_key # 通过modified属性可以明确告诉session对象它已经被修改 request.session.modified = True
基于类的视图
使用基于类的视图
views.py
from django.shortcuts import render, redirect from . import models from django import views class Login(views.View): # 重写get()方法,前端get请求执行此方法 def get(self, request, *args, **kwargs): return render(request, 'myapp/login.html') # 重写post()方法,前端post请求执行此方法 def post(self, request, *args, **kwargs): # 从前端请求获取用户信息 username = request.POST.get('username') password = request.POST.get('password') # 从数据库中获取与用户信息相同的对象个数 user_auth = models.Administrator.objects.filter(username=username, password=password).count() # 如果用户信息验证通过 if user_auth: # 设置session request.session['username'] = username request.session['password'] = password request.session['active'] = True # 实例化重定向对象 httpresponse = redirect('/app/index.html') # 返回重定向 return httpresponse else: # 用户验证不通过,返回错误信息 login_error = '登陆失败' return render(request, 'myapp/login.html', {'login_error': login_error})
当使用类封装view函数后,在URLconf中将配置类属性as_view() 作为参数来调用。
当一个请求到达的 URL 被关联模式匹配时,这个类方法返回一个函数。这个函数创建一个类的实例,调用 setup() 初始化它的属性,然后调用 dispatch() 方法。观察请求并决定它是GET和POST
from django.contrib import admin from django.urls import path, include, re_path from myapp.views import Login urlpatterns = [ path('admin/', admin.site.urls), re_path(r'login.html$', Login.as_view()), ]
装饰类
类上的方法与独立函数完全不同,因此不能应用函数装饰器到方法上,需要先将它转换为方法装饰器。method_decorator装饰器转换函数。
假设需要定义两个装饰器,可以把两个装饰器防入list中,然后传入method_decorator()中。
from django.shortcuts import render, redirect from django import views from django.utils.decorators import method_decorator def is_login(f): def inner(request, *args): # 获取请求中的session信息 username = request.session.get('username') # 如果存在session信息,返回执行函数 if username: return f(request, *args) # 如果不存在则跳转至登陆页面 else: return redirect('/login.html') return inner class Index(views.View): @method_decorator(is_login) def get(self, request): session = request.session.get('username') return render(request, 'myapp/index.html', {'user': session})
也可以直接把装饰器加在类上,然后参数name指定被装饰的方法
@method_decorator(is_login, name='get') class Index(views.View): def get(self, request): session = request.session.get('username') return render(request, 'myapp/index.html', {'user': session})
如果一个类的所有的请求方法都需要加装饰器,可以直在dispatch方法前添加;因为当请求到达时,会先调用dispatch方法,判断请求方法,再去调用对应的方法。
class Index(views.View): @method_decorator(is_login) def dispatch(self, request, *args, **kwargs): #返回父类dispatch方法结果 return super().dispatch(request, *args, **kwargs) def get(self, request): session = request.session.get('username') print(session) return render(request, 'myapp/index.html', {'user': session})