什么是视图?
视图就是应用中views.py文件中的函数,视图函数的第一个参数必须是request(HttpRequest)对象。返回的时候必须返回一个HttpResponse对象或子对象(包含HttpResponse)作为响应。子对象(render,redirect)。返回子对象预先接收HttpRequest,进行逻辑处理,返回web响应HttpResponse给请求者。(响应内容HTML内容,404错误,重定向,json数据)
使用视图时的两个步骤:
1、配置URLconf即配置路由
2、在应用中的views.py中定义视图
项目准备:
创建项目-----创建应用------安装应用(设置里面的INSTALL__APPS)-----配置模板路径-----本地化(语言,时区)------mysql数据库(配置导入包,替换项目自带的数据库)------URLconfig------视图
mysql数据库使用之前的bookdb:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # 数据库引擎 'NAME': 'bookdb', # 数据库名称 'HOST': 'localhost', # 数据库主机(建议使用主机真实IP) 'PORT': '3306', # 数据库端口 'USER': 'root', # 数据库用户名 'PASSWORD': '', # 数据库密码 } }
项目准备好后,测试逻辑。即随便写个路由然后到视图函数随便返回一个字符串,如果返回到浏览器,说明项目逻辑OK。
URL配置
开发者通过在浏览器的地址范围输入网址请求网站,对于Django开发的网站,由哪一个视图进行处理请求,是由网址匹配找到的
配置URLconf
1.在setings.py中去看指定网址配置是否正确。
ROOT_URLCONF = "项目名字.urls"
2、项目中的urls.py
匹配成功后,包含到应用的urls.py(现在的新版本不用关注这里啦,如果版本低,那么出问题需要知道)
url(正则,include(应用.urls))
3、应用中的urls.py
匹配成功后,调用对应的views.py
#这是常规匹配 path('admin/', admin.site.urls), re_path("^$",views.index), #下面这个是正则匹配
URL中取值
如果想从url中获取值,需要在正则表达式中使用分组。
获取值的两种方式:
1、位置参数(参数的位置不能错)
2、关键字参数
注意:两种参数不能混合使用,在一个正则表达式中只能使用一种参数形式
位置参数
例如用上面两种方式获取URL值,提出188和545121 http://127.0.0.1:8000/188/545121/
1、应用中的urls.py
re_path("^(d+)/(d+)/$",views.index),
2、views.py:
#位置参数的应用 def index(request,num1,num2): #构造上下文 content = {"num1":num1,"num2":num2} return render(request,"Book/index.html",content)
3、模板中的代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>位置参数</title> </head> <body> <ur> <li>{{ num1 }}</li> <li>{{ num2 }}</li> </ur> </body> </html>
关键字参数
1、应用中的urls.py
其中?P<name>的部分表示为这个参数的名称为(name)(自定义名称)
#关键字参数 re_path("^(?P<number1>d+)/(?P<number2>d+)/$",views.index),
2、views.py
#关键字参数的应用 def index(request,number2,number1): #构造上下文 content = {"number2":number2,"number1":number1} return render(request,"Book/index.html",content)
3、模板代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>关键字参数</title> </head> <body> <ur> <li>{{ number2 }}</li> <li>{{ number1 }}</li> </ur> </body> </html>
从结果可以看出,两个位置变化了,说明给参数别明名了,名字的位置不同,参数的位置也跟着变化。
错误视图
Django内置处理HTTP错误的视图,主要错误及视图包括
- 404错误:找不到页面视图
- url匹配不成功会发生404错误
- 400错误:错误的请求视图
- 来自客户端的安全方面非法操作会引发400错误
- 500错误:服务器错误视图
- 在视图中代码运行报错会发生500错误
-
只需要在模板中定义指定html文件即可,不需要配置URLconf和准备视图,但是要配置模板加载路径
404.html
400.html
500.html
- ...
-
创建404模板:创建在
templates
文件夹下 -
定义404模板内容
-
如果想看到错误视图而不是调试信息,需要修改
settings.py
文件的DEBUG
项 -
展示404模板效果
HttpRequest对象
服务器接收到HTTP协议的请求后,会根据报文创建HttpRequest对象,这个HttpRequest对象,是由Django封装好的,专门接收客户端发送的消息。HttpRequest对象属性几乎都是读取内容的。
常见属性
path:一个字符串,表示请求的页面的完整路径,不包含域名
method:一个字符串,表示请求使用的HTTP方法,常用值包括:GET、POST 在浏览器中给出地址发出请求采用get方式,如超链接 在浏览器中点击表单的提交按钮发起请求,如果表单的method设置为post则为post请求
GET:一个类似于字典的QueryDict对象 包含get请求方式的所有参数,?后面的内容
POST:一个类似于字典的QueryDict对象 包含post请求方式的所有参数
FILES:一个类似于字典的QueryDict对象,包含所有的上传文件
COOKIES:一个标准的Python字典,包含所有的cookie,键和值都为字符串
encoding:一个字符串,表示提交的数据的编码方式 如果为None则表示使用浏览器的默认设置,一般为utf-8 这个属性是可写的,可以通过修改它来修改访问表单数据使用的编码,接下来对属性的任何访问将使用新的encoding值
session:一个既可读又可写的类似于字典的对象,表示当前的会话,只有当Django 启用会话的支持时才可用,详细内容见“状态保持”
获取属性
配置URLconf
http://127.0.0.1:8000/test/
path('test/', views.test),
2、views.py
def test(request): #获取属性,构造上下文 content = {"path":request.path,"method":request.method,"GET":request.GET} return render(request,"Book/test.html",content)
3、模板
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>测试</title> </head> <body> <ul> <span>路径:</span><li>{{ path }}</li> <span>请求方法:</span><li>{{ method }}</li> <span>GET属性:</span><li>{{ GET }}</li> </ul> </body> </html>
结果:
QueryDict对象
QueryDict类型的对象不是字典,仅仅是类似字典的对象而已。
相关方法
get()方法:根据键获取值,如果一个键同时拥有多个值将获取最后一个值 如果键不存在则返回None值,可以设置默认值进行后续处理 dict.get('键',默认值) 可简写为 dict['键'] getlist()方法:根据键获取值,值以列表返回,可以获取指定键的所有值,如果键不存在则返回空列表[],可以设置默认值进行后续处理 dict.getlist('键',默认值)
GET属性
HttpRequest对象的GET属性,返回一个类似于字典的QueryDict对象,对象中包含GET请求的所有请求参数。
根据键取值:get(),getlist()
分析:
get请求时url格式,在请求地址末尾使用?,之后以“”键=值“”的格式拼接,多个键值之间以&链接
获取请求参数(http://127.0.0.1:8000/index/?a=10&b=20&c=python
)
# QueryDict类型的对象dict dict = request.GET a = dict.get('a') b = dict.get('b') c = dict.get('c')
获取请求参数一键多值情况(http://127.0.0.1:8000/get/?a=10&b=20&a=python
)
# QueryDict类型的对象dict dict = request.GET # a = dict.get('a') # 返回最后一个值 a = dict.getlist('a') # 返回所有值 b = dict.get('b')
POST属性
使用form表单提交请求时,method方式为post则会发送post请求。(1、需要使用HttpRequest对象的POST属性接收参数,POST属性返回QueryDict类型的对象)
备注:checkbox多选项,name属性的值相同为一组,被选中的项会被提交,出现一键多值情况。
配置URLconf(测试post)
path('test/', views.test),
视图
def test(request): if request.method == "GET": #获取属性,构造上下文 content = {"path":request.path,"method":request.method,"GET":request.GET} return render(request,"Book/test.html",content) else: dict = request.POST uname = dict.get('uname') upassword = dict.get('upassword') sex = dict.get('sex') like = dict.getlist('like') # 一键多值 content = {'uname': uname, 'upassword': upassword, 'sex': sex, 'like': like} return render(request, 'Book/test.html', content)
模板
<form action="/post1/" method="post"> {# Django项目默认会做CSRF安全验证 #} {% csrf_token %} <input type="text" name="uname"> <br> <br> <input type="password" name="upassword"> <br> <br> <input type="radio" name="sex" value="男">男 <input type="radio" name="sex" value="女">女 <br> <br> <input type="checkbox" name="like" value="足球">足球 <input type="checkbox" name="like" value="篮球">篮球 <input type="checkbox" name="like" value="羽毛球">羽毛球 <br> <br> <input type="submit" value="提交"> </form>
从上面可以看出浏览器第二次接收到服务器的响应数据
HttpResponse对象
视图在接受请求并处理后,必须返回HttpResponse对象,或子对象。
常见属性
content:表示返回的内容 charset:表示response采用的编码字符集,默认为utf-8 status_code:返回的HTTP响应状态码 content_type:指定返回数据的的MIME类型,默认为'text/html'
常见方法
init:创建HttpResponse对象后完成返回内容的初始化 write:向响应体中写数据 set_cookie:设置Cookie信息 set_cookie('key', 'value', max_age=None, expires=None)
cookie是网站以键值对格式存储在浏览器中的一段纯文本信息,用于实现用户跟踪 max_age是一个整数,表示在指定秒数后过期 expires是一个datetime或timedelta对象,会话将在这个指定的日期/时间过期 max_age与expires二选一 如果不指定过期时间,默认两个星期后过期
delete_cookie:删除指定的key的Cookie,如果key不存在则什么也不发生 delete_cookie('key')
HttpResponse响应内容示例
1、直接响应数据
return HttpResponse(“OK”)
2、调用模板-简写
from django.shortcuts import render def test(request): # 定义上下文 content= {'key':'value'} # 获取模板,渲染模板,让模板语言执行 return render(request, 'Book/test.html', content)
JsonResponse
继承Httpresponse,被定义在django.http模块中。(接收字典作为参数)
使用场景:
当需要响应json数据给请求者时,需要用到JsonResponse。
他的content-type默认为application/json,响应json格式。
案例:ajax实现网页局部刷新需要使用到JsonResponse响应的json数据
备注:为了更方便,可以利用python中的json模块,序列化数据,在js代码中反序列化数据,也可以实现json数据的传输。
需求实现
1.准备URLconf,视图,模板 2.导入 jquery 静态文件 3.发起ajax请求 4.响应json字典 5.处理json字典,构造html内容
1、准备URLconf,视图,模板
#ajax请求 path('ajax/', views.ajax),
#ajax请求 def ajax(request): return render(request,"Book/ajax.html")
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Ajax</title> </head> <body> <input type="button" id="ajaxbtn" value="ajax_request"> <ul> <li>啦啦</li> <li>你你你</li> <li>我我我</li> <li>他他他</li> </ul> <ul id="test" style="background: red; 100px;height: 100px;"> <li>你好呀</li> <li>我好呀</li> <li>他好呀</li> <li>哈呀好呀</li> </ul> </body> </html>
2、导入jquery静态文件
<head> <meta charset="UTF-8"> <title>Ajax</title> {#导入jquery文件#} <script src="/static/js/jquery-3.4.1.min.js"></script> </head>
配置静态文件加载路径
STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR,"static") ]
静态文件加载成功!
3、发起ajax请求
{#ajax请求json数据#} <script> $(function () { //获取ajaxbtn按钮点击事件 $("#ajaxbtn").click(function () { //ajax请求,参数一:请求地址;参数2:请求回调,response表示请求响应的字典 $.get("/jsondata/",function (response) { alert("收到响应啦"); }); }); }); </script>
4、响应json字典
准备模型类:
#创建书籍信息 class Books(models.Model): name = models.CharField(max_length=20)#书名 pub_data = models.DateField(null=True)#出版日期 #参数max_digits表示总位数 参数decimal_places表示小数位数 price = models.DecimalField(max_digits=8,decimal_places=2)#价格 publish = models.CharField(max_length=20) #外键 将字段定义在多的一端中 级联删除 author = models.ForeignKey(Authors,on_delete=models.CASCADE) #修改表名(元类) class Meta: db_table = "books" def __str__(self): return self.name #创建作者信息表 class Authors(models.Model): name = models.CharField(max_length=20)#作者名字 gender = models.BooleanField(default=True)#性别 age = models.IntegerField()#年龄 addr = models.CharField(max_length=60) tel = models.IntegerField() #元类修改表名 class Meta: db_table = "authors" def __str__(self): return self.name
构造json字典分析
“”“ 原始:book = [book0,book1,book2,book3] 结果:response = {"booklist":[{"name":"大局观"},{"name":"与时间做朋友"},{"name":"稀缺"},{"name":"怎样解题"}]} ”“”
实现
def jsondata(request): #查询所有书籍 books = Books.objects.all() #构造书籍字典 list1 = [] for book in books: list1.append({"name":book.name}) #构造json字典 jsondict = {"booklist":list1} return JsonResponse(jsondict)
5、处理字典,构造html内容
{#ajax请求json数据#} <script> $(function () { //获取ajaxbtn按钮点击事件 $("#ajaxbtn").click(function () { //ajax请求,参数一:请求地址;参数2:请求回调,response表示请求响应的字典 $.get("/jsondata/",function (response) { //删除id="test"的ul里面的li $("#test li").remove(); //获取jsondict字典里面的书籍列表信息 booklist = response.booklist; //获取id="test"的url test_ul = $("#test"); //遍历书籍列表信息,拼接li $.each(booklist,function (i,book) { test_ul.append("<li>"+book.name+"</li>"); }); }); }); }); </script>
HttpResponseRedirect(redirect和这个用法相同)
当一个逻辑处理完成后,不需要向客户端呈现数据,而是转回到其它页面 如添加成功、修改成功、删除成功后显示数据列表,而数据的列表视图已经开发完成,此时不需要重新编写列表的代码,而是转到这个视图就可以
从一个视图转到另外一个视图,就称为重定向
Django中提供了HttpResponseRedirect对象实现重定向功能 这个类继承自HttpResponse,被定义在django.http模块中 from django.shortcuts import render, redirect from django.http import HttpResponse,JsonResponse,HttpResponseRedirect 返回的状态码为302
重定向示例
需求:每次登陆网页成功后都需要跳转到新的页面。
实现:
配置URLconf
path('login/', views.login),
视图
def login(request): #处理登陆逻辑完,跳转页面 return redirect("http:www.baidu.com")
状态保持
浏览器请求服务器是无状态的。
无状态:指一次用户请求时,浏览器、服务器无法知道之前这个用户做过什么,每次请求都是一次新的请求。
无状态原因:浏览器与服务器是使用Socket套接字进行通信的,服务器将请求结果返回给浏览器之后,会关闭当前的Socket连接,而且服务器也会在处理页面完毕之后销毁页面对象。
有时需要保持下来用户浏览的状态,比如用户是否登录过,浏览过哪些商品等
实现状态保持主要有两种方式:
在客户端存储信息使用Cookie
在服务器端存储信息使用Session
Cookie
- Cookie:指某些网站为了辨别用户身份、进行session跟踪而储存在用户本地的数据(通常经过加密)。
- 复数形式Cookies。
- Cookie最早是网景公司的前雇员Lou Montulli在1993年3月的发明。
- Cookie是由服务器端生成,发送给客户端浏览器,浏览器会将Cookie的key/value保存,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)。
- Cookie的key/value可以由服务器端自己定义。
- 应用:
- 最典型的应用是判定注册用户是否已经登录网站,用户可能会得到提示,是否在下一次进入此网站时保留用户信息以便简化登录手续,这些都是Cookie的功用。
- 网站的广告推送,经常遇到访问某个网站时,会弹出小窗口,展示我们曾经在购物网站上看过的商品信息。
- 购物车,用户可能会在一段时间内在同一家网站的不同页面中选择不同的商品,这些信息都会写入Cookie,以便在最后付款时提取信息。
-
提示:
- Cookie是存储在浏览器中的一段纯文本信息,建议不要存储敏感信息如密码,因为电脑上的浏览器可能被其它人使用
- Cookie基于域名安全,不同域名的Cookie是不能互相访问的(比如我访问百度和淘宝使用的是不同的cookie)
-
当浏览器请求某网站时,会将本网站下所有Cookie信息提交给服务器,所以在request中可以读取Cookie信息
Cookie使用
1、设置cookie
response.set_cookie("lishuntao","hello")
2、读取cookie
read_cookie = request.COOKIES["lishuntao"]
3、判断是否存在某个Cookie
if request.COOKIES.has_key("lishuntao"): pass
4、删除Cookie
response.delete_cookie("lishuntao")
Session
- 对于敏感、重要的信息,建议要存储在服务器端,不能存储在浏览器中,如用户名、余额、等级、验证码等信息
- 在服务器端进行状态保持的方案就是
Session
- Session依赖于Cookie
启用Session
Django项目默认启用Session(禁用Session:将Session中间件注释即可)
Session存储方式
Session数据,可以存储在数据库、缓存、Redis等(设置SESSION_ENGINE项指定Session存储方式)
存储在数据库中,默认储存方式。
储存在缓存中:存储在本机内存中,如果丢失则不能找回,比数据库的方式读写更快。
混合存储:优先从本机内容中存取,如果没有则从数据库中存取
如果存储在数据库中,需要在项INSTALLED_APPS中安装Session应用
默认存储Session的数据库
-
迁移后会在数据库中创建出存储Session的表
-
表结构
-
由表结构可知,操作Session包括三个数据:键,值,过期时间
-
常见Session操作
1、设置session
request.session["key"]=value
2、读取session
request.session.get("key",default)
3、删除指定键的值,在存储中只删除某个键对应的值
del request.session["key"]
4、清除所有键的值,在存储中删除所有键对应的值
request.session.clear()
5、清除session数据,在存储中删除所有键值,变成空表
request.session.flush()
6、设置会话的超时时间
request.session.set_expiry(value) #如果value是一个整数,会话将在value秒没有活动后过期 #如果value为0,那么用户会话的Cookie将在用户的浏览器关闭时过期 #如果value为None,那么会话则两个星期后过期
Session依赖于Cookie
在使用Session后,会在Cookie中存储一个sessionid
的数据,每次请求时浏览器都会将这个数据发给服务器,服务器在接收到sessionid
后,会根据这个值找出这个请求者的Session
备注
1. 如果想使用Session,浏览器必须支持Cookie,否则就无法使用Session了
2. 存储Session时,键与Cookie中的`sessionid`相同,值是开发人员设置的键值对信息,进行了base64编码,过期时间由开发人员设置