Django
本篇博客是我在B站学习的笔记。B站教程地址
Django介绍
起源
2005年发布,采用Python语言编写的开源框架。
早期的时候Django主做新闻和内容管理的
重量级的Python Web框架,Django配备了常用的大部分组件
组件
Django包含的组件如下:
基本配置文件/路由系统
模型层(M)/模板层(T)/视图层(V)
Cookies和Session
分页及发邮件
Admin管理后台
用途
用途一:网站/微信公众号/小程序后端开发
用途二:人工智能平台融合
相关文档
Django官网:https://www.djangoproject.com/
Django中文文档参考网站:https://yiyibooks.cn/
安装
Django与其支持的Python版本:https://docs.djangoproject.com/zh-hans/3.2/faq/install/#faq-python-version-support
具体安装操作
以下操作全部都是在你pip能正常使用的前提下,没有更换pip源,建议换个国内源
Windows
用管理员身份打开cmd运行以下命令
安装
pip install django
验证是否安装成功
pip freeze|findstr -i Django
出现以下结果,则安装成功
Linux
打开终端输入以下命令
安装
sudo pip install django
验证安装是否成功
sudo pip freeze|grep -i 'Django'
出现以下结果,则安装成功
离线安装
1、官网下载离线安装包
2、解压安装包
3、进入Django目录
4、执行安装
python setup.py install
5. 检查是否安装成功(方法同上)
Django项目结构1
创建项目
成功安装Django后,终端会有django-admin命令
执行 django-admin startproject [项目名]
即可创建出对应项目文件夹
例如:
终端执行 django-admin startproject mySite1
则创建出mySite1项目
启动服务
1.、终端进入到项目文件夹
2、进入到项目文件夹后,执行 python manage.py runserver
启动django服务【注:该启动方式下,Django在前台启动服务,默认监听8000端口】
3、浏览器访问
http://127.0.0.1:8000/
可以看到django的启动页面。【如果想更换端口,则可以用 python manage.py runserver:[端口号]
更改】
关闭服务
方式1
在runserver启动终端下执行Ctrl+C
可关闭Django服务
方式2
在其他终端下
1、windows执行
netstat -ano|findstr [你的Django端口号]
查询出Django的进程id
linux执行
sudo lsof -i:8000
查询出Django的进程id
2、执行 kill -9 [对应Django进程的id]
启动常见问题
启动报错
Error:That port is already in use
问题原因:端口已被使用,证明当前Django启动时,默认监听的8000端口已被其他进程占用
解决方案:参考更换端口
结构解析
名为mysite1的项目,结构如下
db.sqlite3:创建项目的时候没有,第一次启动服务的时候被创建。Django默认的数据库存储文件。
manage.py:Django所有子命令的入口。例如:
python manage.py runserver
启动服务
python manage.py startapp
创建应用
python manage.py migrate
数据库迁移
......
直接执行python manage.py
可列出所有Django子命令
mysite1(项目同名文件夹):
__ init __:Python包的初始化文件
wsgi.py:Web服务网关的配置文件 - Django正式启动时,需要用到。
urls.py:项目的主路由配置 - HTTP请求进入Django时,优先调用该文件。
settings.py:项目的配置文件 - 包含项目启动时需要的配置。
Django项目结构2
settings.py
settings.py包含了Django项目启动的所有配置项
配置项分为共有配置和自定义配置
配置项格式,例:BASE_DIR = "XXX"
,其中等号前为全局变量名,必须全部为大写
公有配置 - Django官方提供的基础配置
https://docs.djangoproject.com/en/4.0/ref/settings/
这个链接是我写这篇博客的时候最新的,以后随着时间的推移,大家可以到Django官网自行查找。、
常见全局变量
BASE_DIR = Path(__file__).resolve().parent.parent
BASE_DIR基础路径,__file__代表的是settings.py文件,那么Path(file).resolve()的结果将会是settings.py文件的绝对路径;然后取其父目录的父目录,也就是django-admin创建项目之后的路径。
DEBUG
启动模式,取值有两个
True:调试模式
调试模式特点:
1、检测代码改动后,立刻重启服务生效。
2、提供报错页面
False:正式启动模式/上线模式
ALLOWED_HOSTS
过滤请求头Host头
[]
空列表,表示只有请求头中host为127.0.0.1,localhost能访问本项目 -DEBUG=True时有效
['*']
表示任何请求头的host都能访问到当前项目
['指定ip','....(ip)']
表示只有当前指定host头的值能访问当前项目
示例:
如果想要在局域网其他主机也能访问此主机
python manage.py runserver 0.0.0.0:5000
指定网络设备如果内网环境下其他主机想正常访问该站点需要添加如下配置项
ALLOWED_HOSTS=["服务器内网IP"]
ROOT_URLCONF
表示Django主路由配置文件
DATABASES
Django数据库配置文件
LANGUAGE_CODE
Django语言配置
英文:en-us
中文:zh-Hans
TIME_ZONE
Django时区配置
中国时区:Asia/Shanghai
INSTALLED_APPS
指定当前项目中安装的应用列表
MIDDLEWARE
用于注册中间件
TEMPLATES
用于指定模板的配置信息
settings.py
中也可以添加开发文员自动逸的配置
配置建议:名字尽量个性化(以防止覆盖掉公有配置),例如:* ALIPAY_KEY = ''XXXX
settings.py
中的所有配置项,都可以按需的在代码中引入
引入方式:*
from django.conf import settings
url和视图函数
URL-结构
定义:
即统一资源定位符 Uniform Resource Locator
作用:
用来表示互联网上某个资源的地址
URL的一般语法格式为:(注:[]代表其中的内容可省略)
protocol://hostname[:port]/path[?query][#fragment]
[?query]
查询字符串
[#fragment]
锚点,快速定位。
例如:
http://tts.tmooc.cn/video/showVideo?menuld=657421&version=Aid999#subject
protocol(协议):
http通过HTTP协议访问该资源。格式:http://
https通过安全的HTTPS协议访问该资源。格式:https://
file资源是本地计算机上的文件。格式:file://
hostname(主机名):
是指存放资源的服务器的域名系统(DNS)主机名、域名或IP地址
port(端口号)
整数,可选,省略时使用方案的默认端口
各种传输协议都有默认的端口号
path(路由地址)
由零或多个“/”符号隔开的字符串,一般用来表示主机上的一个目录或文件地址。路由地址决定了服务器端如何处理这个请求。
query(查询)
可选,用于给动态网页传递参数,可有多个参数,用"&"符号隔开,每个参数的名和值用“=”符号隔开。
fragment(信息片段)
字符串,用于指定网络资源中的片段。例如,一个网页中有多个名词解释,可使用fragment直接定位到某一名词解释。
处理URL请求
浏览器 地址栏 -> http://127.0.0.1:8000/page/2003/(网站地址)
1、Django从配置文件中根据ROOT_URLCONF找到主路由文件;默认情况下,该文件在项目同名目录下的urls;例如mysite1/mysite1/urls.py
2、Django加载主路由文件中的urlpatterns变量[包含很多路由的数组]
3、依次匹配urlpatterns中的path,匹配到第一个合适的中断后续匹配。
4、匹配成功-调用对应的视图函数处理请求,返回响应
5、匹配失败-返回404响应
如下图中所示,引号括起来的是路由地址,逗号隔开的不带引号的部分是相应的视图函数
urls.py样例
from django.contrib import admin from django.urls import path from . import views urlpatterns = [ path('admin/', admin.site.urls), path("page/2003",views.page_2003_view), #path("page/1",views.page1), #path("page/2",views.page2 ), path("page/<int:pg>",views.pagen_view), path("test_request",views.test_request) ]
视图函数
视图函数是用于接受一个浏览器请求(HttpRequest对象)并通过HttpResponse对象返回响应的函数。此函数可以接收浏览器请求并根据业务逻辑返回相应的响应内容给浏览器.
语法
def xxx_view[函数名](request,[其他参数,....]): return HttpResponse
例如:
file(文件位置):<项目同名文件夹下>/views.py
路由配置1
路由配置
settings.py中的ROOT_URLCONF制定了主路由配置列表urlpatterns的文件位置
file(文件位置):<项目同名文件夹下>/urls.py
路由配置-path
path()函数
导入 - from django.urls import path
语法 - path(route,views,name=None)
参数:
1、route:字符串类型,匹配的请求路径
2、views:指定路径所对应的视图处理函数的名称
3、name:为地址起别名,在模板中地址反向解析时使用
例如:
path("page/2003",views.page_2003_view)
路由配置 - path - 转换器
path转换器
语法:<转换器类型:自定义名>
作用:若转换器类型匹配到对应类型的数据,则将数据按照关键字传参的方式传递给视图函数
例如: path('page/<int:page>',views.xxx)
常见转换器类型
路由配置2
re_path()
re_path()函数
在url的匹配过程中可以使用正则表达式进行精准匹配
语法:
re_path(reg,view,name=xxx)
正则表达式命名分组模式(?P<name>pattern);
匹配提取参数后用关键字传参方式传递给视图函数
正则表达式
样例:
请求响应
定义
请求是指浏览器端通过HTTP协议发送给服务器端的数据
响应是指服务器端接收到请求后做相应的处理后在回复给浏览器端的数据
请求
样例
请求中的方法
- 根据HTTP标准,HTTP请求可以使用多种请求方法。
- HTTP1.0定义了三种请求方法:GET、POST和HEAD(最常用)
- HTTP1.1新增了五种请求方法:OPTIONS、PUT、DELETE、TRACE和CONNECT
Django中的请求
- 请求在Django中实则就是视图函数的第一个参数,即
HttpRequest
对象 - Django接收到http协议的请求后,会根据请求数据报文创建
HttpRequest
对象 HttpRequest
对象通过属性描述了请求的所有相关信息
HttpRequest
常见属性:
- path_info:URL字符串
- method:字符串,表示HTTP请求方法,常用值:'GET'、'POST'
- GET:QueryDict查询字典的对象,包含get请求方式的所有数据
- POST:QueryDict查询字典的对象,包含post请求方式的所有数据
- FILES:类似于字典的对象,包含所有的上传文件信息。
- COOKIES:Python字典,包含所有的cookie,键和值都为字符串
- session:类似于字典的对象,表示当前的会话
- body:字符串,请求体的内容(POST或PUT)
- scheme:请求协议('http'/'https')
- request.get_full_path():请求的完整路径
- request.MATE:请求中的元数据(消息头)
- request.MATE['REMOTE_ADDR']:客户端IP地址
以下方法,可以将上面介绍的属性打出来
def test_request(request):
print("path info is ",request.path_info)
print("method is",request.method)
print("Get info is ",request.GET)
print("full path is ",request.get_full_path)
return HttpResponse("test request is OK")
响应
响应示例
常见的HTTP状态码(HTTP Status Code):
-200-请求成功
-301-永久重定向-资源(网页等)被永久转移到其他URL
-302-临时重定向
-404-请求的资源(网页等)不存在
-500-内部服务器错误
状态码规律
HTTP状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字没有分类的作用。HTTP状态码共分为5种类型:
Django中的响应对象
构造函数格式:
HttpResponse(content=响应体,content_type=响应体数据类型,status=状态码)
作用:
向客户端浏览器返回响应,同时携带响应体内容
常用的Content-Type如下:
-'text/html'(默认的,html文件)
-'text/plain'(纯文本的)
-'text/css'(css文件)
-'text/javascript'(js文件)
-'multipart/form-data'(文件提交)
-'application/json'(json传输)
-'application/xml'(xml文件)
HttpResponse子类:
GET和POST请求
定义
- 无论是GET还是POST,统一都由视图函数接收请求,通过判断request.method区分具体的请求动作
- 样例
if request.method == 'GET': 处理GET请求时的业务逻辑 elif request.method == 'POST': 处理POST请求的业务逻辑 else: 其他请求业务逻辑
GET处理
- GET请求动作,一般用于向服务器获取数据
- 能够产生GET请求的场景:
- 浏览器地址栏中输入URL,回车后
- form表单中的method为get
GET请求方式中,如果有数据需要传递给服务器,通常会用查询字符串(Query String)传递 [注意:不要传递敏感数据]
URL 格式:xxx?参数名1=值1&参数名2=值2
例如:http://127.0.0.1:8000/page1?a=100&b=200
服务器端接收参数
获取客户端请求GET请求提交的数据
- 方法示例:
POST处理
- POST请求动作,一般用于向服务器提交大量/隐私数据
- 客户端通过表单等POST请求将数据传递给服务器端,如:
-
服务器端接收参数
通过request.method来判断是否为POST请求,如:使用post方式接收客户端数据
取消csrf验证,否则Django将会拒绝客户端发来的POST请求,报403响应
-
取消csrf验证
*禁止掉settings.py中MIDDLEWARE中的CsrfViewsMiddleWare
Django的设计模式及模板层
MVC和MTV
MVC代表Model-View-Controller(模型-视图-控制器)模式。
- M模板层(Model),主要用于对数据库层的封装
- V视图层(View),用于向用户展示结果(WHAT+HOW)
- C控制(Controller),用于处理请求、获取数据、返回结果(重要)
作用:降低模块间的耦合度(解耦)
MTV代表Model-Template-View(模型-模板-视图)模式。
- M模型层(Model)负责与数据库交互
- T模板层(Template)负责呈现内容到浏览器(HOW)
- V视图层(View)是核心,负责接受请求、获取数据、返回结果(WHAT)
作用:降低模块间的耦合度(解耦)
什么是模板
1、 模板是可以根据字典数据动态变化的html网页
2、 模板可以根据视图中传递的字典数据动态生成相应的HTML网页
模板配置
创建模板文件夹<项目名>/templates
在settings.py中TEMPLATES配置项
1、 BACKEND:指定模板引擎
2、 DIRS:模板的搜索目录
3、 APP_DIRS:是否要在应用中的templates文件夹中搜索模板文件
4、 OPTIONS:有关模板的选项
配置项中需要修改部分
设置DIRS-'DIRS':[os.path.join.(BASE_DIR,'templates')],
模板的加载方式
方案1-通过loader获取模板,通过HttpResponse进行响应
在视图函数中
from django.template import loader
# 1、通过loader加载模板
t = loader.get_template("模板文件名")
# 2、将t转换成HTML字符串
html = t.render(字典数据)
# 3、用响应对象将转换的字符串内容返回给浏览器
return HttpResponse(html)
方案2-使用render()直接加载并响应模板
在视图函数中
def test_web(request):
from django.shortcuts import render
return render(request,'模板文件名',字典数据)
视图层与模板层之间的交互
1、 视图函数中可以将Python变量封装到字典中传递到模板
样例:
def xxx_view(request):
from django.shortcuts import render
dic = {
"变量1":"值1",
"变量2":"值2"
}
return render(request,'xxx.html',dic)
2、 模板中,我们可以用{{变量名}}
的语法调用视图传进来的变量。通俗讲就是在html界面中直接调用后端传进来的变量。
例如:
模板层-变量和标签
模板的变量
这里对应上面视图层与模板层之间的交互中的两种方法
1、视图函数中可以将Python变量封装到到字典中传递到模板上
样例:
def xxx_view(request):
from django.shortcuts import render
dic = {
"变量1":"值1",
"变量2":"值2"
}
return render(request,'xxx.html',dic)
能传递到模板中的数据类型
- str-字符串
- int-整型
- list-数组
- tuple-元组
- dict-字典
- func-方法
- obj-类实例化的对象
2、在模板中使用变量语法
{{变量名}}
{{变量名.index}}
{{变量名.key}}
{{对象.方法}}
{{函数名}}
模板标签
作用:将一些服务器的功能嵌入到模板中,例如流程控制等
标签语法
{% 标签 %}
......
{% 结束标签 %}
if标签
语法:
{% if 条件表达式1 %}
......
{% elif 条件表达式2 %}
......
{% elif 条件表达式3 %}
......
{% else %}
...
{% endif %}
注意:
1、if条件表达式里可以用的运算符 ==,!=,<,>,<=,>=,in,not in,is,is not,not,and,or
2、在if标记中使用实际括号是无效的语法。如果您需要它们指示优先级,则应使用嵌套的if标记。
官方文档
for标签
语法:
{% for 变量 in 可迭代对象 %}
...循环语句
{% empty %}
...可迭代对象无数据时填充的语句
{% endfor %}
官方文档
内置变量-forloop
这个forloop内置变量只能写在for循环里,否则就会报错
模板层-过滤器和继承
模板层-过滤器
定义:在变量输出时对变量的值进行处理
作用:可以通过使用过滤器来改变变量的输出显示
语法:{{变量|过滤器1:'参数值1'|过滤器2:'参数值2'...}}
官方文档
常用过滤器:
模板层-继承
定义:模板继承可以使用父模板的内容重用,子模版直接继承父模板的全部内容并可以覆盖父模板中相应的块
语法-父模板中:
- 定义父模板中的块block标签
- 标识出哪些在子模块中是允许被修改的
- block标签:在父模板中定义,可以在子模版中覆盖
语法-子模版中: - 继承模板extends标签(写在模板文件的第一行)
例如{% extend 'base.html' %}
*子模版重写父模板中的内容块
{% block block_name %}
子模板块用来覆盖父模板快中 block_name 块的内容
{% endblock block_name %}
重写的覆盖规则
- 不重写,将按照父模板的效果显示
- 重写,将按照重写效果显示
注意 - 模板继承时,服务器端的动态内容无法继承
参考文档
url反向解析
再谈url
代码中url出现的位置
1、模板【html中】
1、
<a href='url'>超链接</a>
点击后 页面跳转至url
2、
<form action='url' method='post'>
form表单中的数据 用post方法提交至url
2、视图函数中-302跳转 HttpResponseRedirect('url')
将用户地址栏中的地址跳转到url
代码中url书写规范
1、绝对地址
例如:http://127.0.0.1:8000/page/1
2、相对地址
1、'/page/1' - '/'开头的相对地址,浏览器会把当前地址栏里的协议,ip和端口加上这个地址,作为最终访问地址,即如果当前页面地址栏为http://127.0.0.1:8000/page/3
;当前相对地址最终结果为http://127.0.0.1:8000
+/page/1
2、'page/1' - 没有“/”开头的相对地址,浏览器会根据当前url的最后一个“/”之前的内容加上该相对地址作为最终访问地址,例如当前地址栏为http://127.0.0.1:8000/topic/detail
;则该相对地址最终结果为http://127.0.0.1:8000/topic
+page/1
url反向解析
定义:url 反向解析是指在视图或模板中,用path定义的名称来动态查找或计算出相应的路由。
path函数的语法
- path(route,views,name="别名")
- path('page',view.page_view,name='page_url')
根据path中的name=
关键字传参给url确定了一个唯一确定的名字,在模板或视图中,可以通过这个名字反向推断出此url信息
模板中 - 通过url标签实现地址的反向解析
{% url '别名' %}
{% url '别名' '参数值1' '参数值2' %}
For example:
{% url 'pagen' '400' %}
{% url 'person' age='18' name='vh' %}
在视图函数中 -> 可调用django中的reverse方法进行反向解析
def test_reverse(request):
from django.urls import reverse
reverse('别名',args=[],kwargs={})
#例如:
print(reverse('pagen',args=[300]))
print(reverse('person',kwargs={'name':'xixi','age':18}))
静态文件
什么是静态文件?
-如:图片,css,js,音频,视频
静态文件配置
静态文件配置-settings.py中
1、配置静态文件的访问路径【该配置默认存在】
- 通过那个url地址找到静态文件
- STATIC_URL = '/static/'
- 说明:
指定访问静态文件时是需要通过/static/xxx
或http://127.0.0.1:8000/static/xxx
[xxx表示具体的静态资源位置]
2、配置静态文件的存储路径STATICFILES_DIRS
STATICFILES_DIRS
保存的是静态文件在服务器端的存储位置
#file:settings.py
STATICFILES_DIRS = (os.path.join(BASE_DIR,'static'),)
#配置一个参数的时候,逗号一定要带。
静态文件访问
模板中访问静态文件-img标签为例
方案1-直接拼接访问路径
<img src="/static/images/lena.jpg">
<--或者-->
<img src="http://127.0.0.1:8000/static/images/lena.jpg">
方案2-通过{% static %}标签访问静态文件
1、加载static - {% load static %}
2、使用静态资源-{% static '静态资源路径' %}
3、样例
<img src="{% static 'images/lena.jpg' %}">
Django应用及分布式路由
应用
什么是应用?
- 应用在Django项目中是一个独立的业务模块,可以包含自己的路由,视图,模板,模型
创建应用
1、 用manage.py
中的子命令startapp
创建应用文件夹
python manage.py startapp 应用名
命令执行完成后会出现相应的文件夹,例如创建名为music的应用
2、在settings.py
的INSTALLED_APPS
列表中配置安装此应用
3、settings.py
配置样例
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
#以上内容为django自动配置的内容,不用管
#下面配置自己创建的应用
'user',#用户信息模块
'music',#音乐模块
]
分布式路由
Django中,主路由配置文件(urls.py)可以不处理用户具体路由,主路由的配置文件可以做请求的分发(分布式请求处理)。具体的请求可以由各自的应用来进行处理。
配置分布式路由
1、主路由中调用include
函数
语法:include('app名字.url模块名')
作用:用于将当前路由转到各个应用的路由配置文件的urlpatterns进行分布式处理
以http://127.0.0.1:8000/music/index
为例
from . import views
from django.urls import include
urlpatterns = [
path('admin/', admin.site.urls),
path('music/',include('music.urls'))
]
2、应用下配置urls.py
应用下手动创建urls.py
文件,变量内容结构(具体的路由规则根据实际需求编写)同主路由完全一样.
应用的路由已经有主路由配置,所以这里的路由只需要配置应用内路由即可。
例如,完整的地址是:http://127.0.0.1:8000/music/index
主路由配置到http://127.0.0.1:8000/music
,子路由配置到:/index
应用下的模板
应用内部可以配置模板目录
1、应用文件夹下手动创建templates
文件夹
2、settings.py中开启应用模板功能
TEMPLATE配置项中的'APP_DIRS'值为True即可
应用下templates和外层templates都存在时,django的查找模板规则:
1、优先查找外层templates目录下的模板
2、按INSTALLED_APPS配置下的应用顺序逐层查找
这里有个问题,比如主页文件index.html之前的应用的模板文件夹也有,根据上面的匹配规则不就产生歧义,不能准确的找到我们需要的文件了吗?
解决办法是在应用的templates模板文件夹下创建一个与应用同名的文件夹,将模板文件放在此文件夹下。
模型层及ORM介绍
模型层
模型层-定义
-
回顾Django MTV
![](/i/l/?n=22&i=blog/1759058/202207/1759058-20220724194748984-626946983.png)
-
模型层-负责跟数据库之间进行通信
Django配置mysql
-
安装 mysqlclient[Django 需要 mysqlclient 1.4.0 或更高版本。目前(2022.07.25)mysqlclient官方最高版本为2.1.1]
Django官方文档关于mysql连接部分
mysqlclient官方界面 -
Linux(ubuntu):
1、安装前确认ubuntu是否已安装python3-dev
和default-libmysqlclient-dev
sudo apt list --installed | grep -E 'libmysqlclient-dev|python3-dev'
2、若上面命令没有输出如图所示结果,则需要安装
安装命令(Debian系): sudo apt-get install python3-dev default-libmysqlclient-dev build-essential
至此相关依赖已解决完,下面正式安装mysqlclient
命令:pip install mysqlclient
Windows:
直接执行:pip install mysqlclient
- 创建数据库
进入mysql数据库执行
create database 数据库名 default charset utf8
通常数据库名跟项目名保持一致 - settings.py里进行数据库的配置
- 修改
DATABASES
配置项的内容,由sqlite3
变为mysql
- 修改
- 补充:
* ENGINE - 指定数据库存储引擎
django.db.backends.mysql
django.db.backends.sqlite3
django.db.backends.oracle
django.db.backends.postgresql
* NAME - 指定要连接的数据库的名称
* USER - 指定登录到数据库的用户名
* PASSWORD - 数据库的密码
* HOST/PORT - 连接具体数据库的 IP 和 端口
什么是模型
- 模型是一个Python类,它是由
django.db.models.Model
派生出的子类 - 一个模型类代表数据库中的一张数据表
- 模型类中每一个类属性都代表数据库中的一个字段
- 模型是数据交互的接口,是表示和操作数据库的方法和方式
ORM框架
定义:ORM(Object Relational Mapping)即对象关系映射,它是一种程序技术,它允许你使用类和对象对数据库进行操作,从而避免通过SQL语句操作数据库
作用:
1、建立模型类和表之间的对应关系,允许我们通过面向对象的方式来操作数据库。
2、根据设计的模型类生成数据库中的表格
3、通过简单的配置就可以进行数据库的切换
优点:
* 只需要面向对象编程,不需要面向数据库编写代码
* 对数据库的操作都转化成对类属性和方法的操作
* 不用编写各种数据库的sql语句
* 实现了数据模型与数据库的解耦,屏蔽了不同数据库操作上的差异.
* 不在关注用的是mysql、oracle......等数据库的内部细节.
* 通过简单的配置就可以轻松更换数据库,而不需要修改代码
缺点:
* 对复杂业务,使用成本较高
* 根据对象的操作转换成SQL语句,根据查询的结果转化成对象,在映射过程中有性能损失。
映射关系:
模型示例
此示例为添加一个bookstore_book
数据表来存放图书馆中数目信息
1、添加一个app并注册app
2、添加模型类
模型类代码示例:
# file:bookstore/models.py
from django.db import models
# Create your models here.
class Book(models.Model):
title = models.CharField("书名",max_length=50,default='')
price = models.DecimalField("定价",max_digits=7,decimal_places=2,default=0.0)
3、数据库迁移
- 迁移是Django同步你对模型所做更改(添加字段,删除模型等)到您的数据据库模式的方式
1、生成迁移文件 - 执行python manage.py makemigrations
将应用下的models.py文件生成一个中间文件,并保存在migrations文件夹中
2、执行迁移脚本程序 - 执行python manage.py migrate
执行迁移程序实现迁移。将每个应用下的migrations目录中的中间文件同步回数据库
模型类 - 创建
from django.db import models
# Create your models here.
class 模型类名(models.Model):
字段名 = models.字段类型(字段选项)
ORM-基础字段及选项1
ORM框架
映射图
创建模型类流程
- 创建应用
- 在应用下的
models.py
中编写模型类
from django.db import models
# Create your models here.
class 模型类名(models.Model):
字段名 = models.字段类型(字段选项)
- 迁移同步
makemigrations&migrate
任何关于表结构的修改,务必在对应模型类上修改
例:为bookstore_book
表添加一个名为info的字段varchar(100)
解决方案:
1、模型类中添加对应类属性
2、执行数据库迁移
字段类型
BooleanField()
- 数据库类型:tinyint(1)
- 编程语言中:使用True或False来表示值
- 在数据库中:使用1或0来表示具体的值
CharField()
- 数据库类型:varchar
- 注意:必须要指定
max_length
参数值。
DataField()
- 数据库类型:date
- 作用:表示日期
- 参数:
1、auto_now
每次保存对象时,自动设置该字段为当前时间(取值:True/False)。
2、auto_now_add
当对象第一次被创建时自动设置当前时间(取值:True/False)。
3、default
设置当前时间(取值:字符串格式时间如:'2019-6-1')。
以上三个参数只能多选一
DataTimeFiled()
- 数据库类型:
datetime(6)
- 作用:表示日期和时间
- 参数与
DateField
一样
- 数据库类型:
FloatField()
- 数据库类型:
double
- 编程语言中和数据库中都使用小数表示值
- 数据库类型:
DecimalField()
- 数据库类型:
decimal(x,y)
- 编程语言中:使用小数表示该列的值
- 在数据库中:使用小数
- 参数:
max_digits
:位数总数,包括小数点后的位数。该值必须大于等于decimal_places
。
decimal_places
:小数点后的数字数量
- 数据库类型:
EmailField()
- 数据库类型:
varchar
- 编程语言和数据库中使用字符串
- 数据库类型:
IntegerField()
- 数据库类型:
int
- 编程语言和数据库中使用整数
- 数据库类型:
ImageField()
- 数据库类型:
varchar(100)
- 作用:在数据库中为了保存图片的路径
- 编程语言和数据库中使用字符串
- 数据库类型:
TextField()
- 数据库类型:
longtext
- 作用:表示不定长的字符数据
- 数据库类型:
- 官方文档
ORM-基础字段及选项2
模型类定义
from django.db import models
# Create your models here.
class 模型类名(models.Model):
字段名 = models.字段类型(字段选项)
模型类字段选项
- 字段选项,指定创建的列的额外的信息
- 允许出现多个字段选项,多个选项之间使用逗号隔开
primary_key
- 如果设置
True
,表示该列为主键,如果指定一个字段为主键,则此数据库表不会创建id字段
- 如果设置
blank
- 设置为
True
时,字段可以为空。设置为False
时,字段是必须填写的
- 设置为
null
- 如果设置为
True
表示该列值允许为空。 - 默认为
False
,如果此选项为False建议加入default
选项来设置默认值
- 如果设置为
default
- 设置所在列的默认值,如果字段选项
null=False
建议添加此项
- 设置所在列的默认值,如果字段选项
db_index
- 如果设置为
True
,表示为该列增加索引
- 如果设置为
unique
- 如果设置为
True
,表示该字段在数据库中的值必须是唯一(不能重复出现的)
- 如果设置为
db_column
- 指定列的名称,如果不指定的话则采用属性名作为列名
verbose_name
- 设置此字段在
admin
界面上的显示名称
字段选项样例
- 设置此字段在
官方文档
ps:修改过字段选项【添加或更改】均要执行makemigrations
和migrate
模型类-Meta类
定义
使用内部Meta
类来给模型赋予属性,Meta
类下有很多内建的类属性,可对模型类做一些控制
示例:
ORM-基础操作-创建数据
常见问题处理
- 问题一:当执行
python manage.py makemigrations
出现如下迁移错误时的处理方法
对应的中文
常见问题处理2
- 数据库的迁移文件混乱的解决办法
- 数据库中
django_migrations
表记录了migrate
的'全过程',项目各应用中的migrate
文件应与之对应,否则migrate
会报错。 - 解决方案:
1、删除所有migrations
里所有的000?_XXX.py
(__init__.py
除外)
2、删除数据库,sql >drop database dbname
3、重新创建数据库,sql >create database dbname
4、重新生成migrations
里所有的000?_XXXX.py
,python manage.py makemigrations
5、重新更新数据库,python manage.py migrate
ORM-创建数据
ORM-操作
基本操作包括增删改查操作,即(CRUD操作)
CRUD是指在做计算处理时的增加(Create)、读取查询(Read)、更新(Update)和删除(Delete)
ORM CRUD 核心 -> 模型类.管理器对象
管理器对象
每个继承自models.Model
的模型类,都会有一个objects对象被同样继承下来。这个对象叫管理器对象。
数据库的增删改查可以通过模型的管理器实现
创建数据
Django ORM 使用一种直观的方式把数据库中的数据表示成Python对象
创建数据中每一条记录就是创建一个数据对象
方案1
MyModel.objects.create(属性1=值1,属性2=值2,......)
- 成功:返回创建好的实体对象
- 失败:抛出异常
方案2
创建MyModel实例对象,并调用save()进行保存
Django Shell
在Django提供了一个交互式的操作项目叫Django Shell 它能够在交互模式用项目工程的代码执行相应的操作
利用Django Shell可以代替编写view的代码来进行直接操作
ps:项目代码发生变化时,重新进入Django Shell
启动方式:python manage.py shell
ORM-查询操作-1
查询简介
- 数据库的查询需要使用管理器对象进行
- 通过MyModel.objects管理器方法调用查询方法
查询方法
- all()方法
用法:MyModel.objects.all()
作用:查询MyModel实体中所有的数据,等同于select * from tablename
返回值:QuerySet
容器对象,内部存放MyModel实例
- 可以在模型类中定义__str__方法,自定义QuerySet中的输出格式
例如 在Book模型类下定义如下:
则在Django shell 中可得到如下显示输出
-
values('列1','列2',......)
用法:MyModel.objects.values(...)
作用:查询部分列的数据并返回,等同于select 列1,列2 from xxx
返回值:QuerySet
返回查询结果容器,容器内存字典,每个字典代表一条数据,格式为:{'列1':值1,'列2':值2}
-
values_list('列1','列2',......)
用法:MyModel.objects.values_list(...)
作用:返回元组形式的查询结果,等同于select 列1,列2 from xxx
返回值:QuerySet
容器对象,内部存放'元组'
会将查询出来的数据封装到元组中,再封装到查询集合QuerySet
中 -
order_by()
用法:MyModel.objects.order_by('列','列')
作用:
与all()方法不同,它会用SQL语句的ORDER BY 子句对查询结果进行根据某个字段选择性的进行排序
说明:
默认是按照升序排序,降序排序则需要在列前增加'-'表示
ORM-查询操作-2
条件查询-方法
- filter(条件)
语法:MyModel.objects.filter(属性1=值1,属性2=值2)
作用:返回包含此条件的全部数据集
返回值:
QuerySet
容器对象,内部存放MyModel
实例
说明:
当多个属性在一起时为“与”关系
filter样例
- exclude(条件)
语法:MyModel.objects.exclude(条件)
作用:返回不包含此条件的全部的数据集
示例:
查询清华大学出版社,定价等于50以外的全部图书
- get(条件)
语法:MyModel.objects.get(条件)
作用:返回满足条件的唯一一条数据
说明:该方法只能返回一条数据,查询结果多余一条数据则抛出Model.MultipleObjectsReturned
异常,查询结果如果没有数据则抛出Model.DoesNotExist
异常
查询谓词
定义:做更灵活的条件查询时需要使用查询谓词
说明:每一个查询谓词是一个独立的查询功能
__exact:等值匹配
示例:
__contains:包含指定值
示例:
__startswith:以XXX开始
__endswith:以XXX结束
__gt:大于指定值
样例
__gte:大于等于
__lt:小于
__lte:小于等于
__in:查找数据是否在指定范围内
样例:
__range:查找数据是否在指定的区间范围内
样例:
ORM-更新操作
更新单个数据
- 修改单个实体的某些字段值的步骤:
1、查
-通过get()
得到要修改的实体对象
2、改
-通过对象.属性的方式修改数据
3、保存
-通过对象.save()保存数据
批量更新数据
- 直接调用
QuerySet
的update(属性=值)
实现批量修改 - 示例:
ORM-删除操作
单个数据删除
步骤
1、查找查询结果对应的一个数据对象
2、调用这个数据对象的delete()方法实现删除
批量删除
步骤
1、查找查询结果集中满足条件的全部QuerySet
查询集合对象
2、调用查询集合对象的delete()
方法实现删除
伪删除
- 通常不会轻易在业务里把数据真正删除掉,取而代之的是做伪删除,即在表中添加一个布尔型字段(is_active),默认是True;执行删除时,将欲删除数据的is_active字段置为False
- 注意:用伪删除时,确保显示数据的地方,均加了is_active=True的过滤查询
F对象和Q对象
F对象
- 一个F对象代表数据库中某条记录的字段的信息
- 作用:
-通常是对数据库中的字段值在不获取的情况下进行操作
-用于类属性(字段)之间的比较 - 语法
- 示例1 更新Book实例中所有的零售价涨10元
- 示例2 对数据库中两个字段的值进行比较,列出哪儿些书的零售价高于定价?
Q对象
当在获取查询结果集使用复杂的逻辑或 | 、逻辑非~等操作时可以借助于Q对象进行操作
如:想找出定价低于20元或清华大学出版社的全部书,可以写成
Q对象在数据包django.db.models中。需要先导入在使用
作用:在条件中用来实现除and(&)以外的or(|)或not(~)操作
运算符:
& 与操作
| 或操作
~ 非操作
语法:
示例
聚合查询和原生数据库操作
聚合查询
聚合查询是指对一个数据表中的一个字段的数据进行部分或全部进行统计查询。例如:查bookstore_book
数据表中的全部书的平均价格,查询所有书的个总个数等,都要使用聚合查询。
聚合查询分为:
- 整表聚合
- 分组聚合
聚合查询-整表聚合
不带分组的聚合查询是指导将全部数据进行集中统计查询
聚合函数[需要导入]:
-导入方法:from django.db.models import *
-聚合函数:Sum,Avg,Count,Max,Min
语法:MyModel.objects.aggregate(结果变量名=聚合函数('列'))
-返回结果:结果变量名和值组成的字典
格式为:{"结果变量名":值}
聚合查询-分组聚合
分组聚合是指通过计算查询结果中每一个对象所联动的对象集合,从而得出总计值(也可以是平均值或总和),即为查询集的每一项生成聚合。
语法:
-QuerySet.annotate(结果变量名=聚合函数('列'))
返回值:
-QuerySet
1、通过先用查询结果MyModel.objects.values
查找查询要分组聚合的列
MyModel.objects.values('列1','列2')
如:
原生数据库操作
Django也可以支持直接调用sql语句的方式通信数据库
查询:使用MyModel.objects.raw()
进行 数据库查询操作
语法:MyModel.objects.raw(sql语句,拼接参数)
返回值:RawQuerySet
集合对象[只支持基础操作,比如循环]
原生数据库操作-SQL注入
使用原生语句时小心SQL注入
定义:用户通过数据上传,将恶意的SQL语句提交给服务器,从而达到攻击效果
案例一:用户在搜索好友的表单框里输入 '1 or 1=1'
攻击结果:可查询出所有用户数据
sql注入防范
原生数据库操作 - cursor
完全跨过模型类操作数据库 - 查询/更新/删除
1、导入cursor所在的包
from django.db import connection
2、用创建cursor类的构造函数创建cursor对象,在使用cusor对象,为保证在出现异常时能释放cursor资源,通常使用with语句进行创建操作
示例
admin后台管理-1
什么是admin管理后台
- django提供了比较完善的后台管理数据库的接口,可供开发过程中调试和测试使用
- django会搜集所有已注册的模型类,为这些模型类提供数据管理界面,供开发者使用
admin配置步骤
- 创建后台管理账号 - 该账号为管理后台最高权限账号
python manage.py createsuperuser
admin后台管理-2
注册自定义模型类
若要自己定义的模型类也能在/admin
后台管理界中显示和管理,需要将自己的类注册到后台管理界面
注册步骤:
1、在应用app中的admin.py中导入注册要管理的模型models类,如:from .models import Book
2、调用admin.site.register方法进行注册,如:admin.site.register(自定义模型类)
修改自定义模型类的数据模式
- 在admin后台管理数据库中对自定义的数据记录都展示为'XXXXobject'类型的记录,不便于阅读和判断
- 在用户自定义的模型类中可以重写
def__str__(self)
:方法解决显示问题,如:
模型管理器类
作用:
为后台管理界面添加便于操作的新功能
说明:
后台管理器类须继承自django.contrib.admin
里的ModelAdmin
类
使用方法
1、在<应用app>/admin.py里定义模型管理器类
2、绑定注册模型管理器和模型类
案例:
1、list_display
去控制哪些字段会显示在Admin的修改列表页面中
2、list_display_links
可以控制list_display
中的字段是否应该链接到对象的“更改”页面
3、list_filter
设置激活Admin
修改列表页面右侧栏中的过滤器
4、search_fields
设置启用Admin
更改列表页面上的搜索框
5、list_editable
设置为模型上的字段名称列表,这将允许在更改列表页面上进行编辑
官方文档
再谈Meta类
通过Meta内嵌类定义模型类的属性,用法如下:
关系映射-1
什么是关系映射
- 在关系型数据库中,通常不会把所有数据都放在同一张表中,不易于扩展,常见关系映射有:
1、一对一映射
如:一个身份证对应一个人
2、一对多映射
如:一个班级可以有多个学生
3、多对多映射
如:一个学生可以报多个课程,一个课程可以有多个学生学习
一对一【创建】
- 一对一是表示现实事物间存在的一对一的对应关系。
- 如:一个家庭只有一个户主,一个男人有一个妻子,一个人有一个唯一的指纹信息等。
- 语法:
OneToOneField(类名,on_delete=XXX)
- 特殊字段选项【必须】
on_delete
- 级联删除
1、models.CASCADE
级联删除。Django模拟SQL约束ON DELETE CASCADE的行为,并删除包含ForeignKey的对象。
2、models.PROTECT
抛出ProtectedError
以阻止被引用对象的删除;[等同于mysql默认的RESTRICT]
3、SET_NULL设置ForeignKey null;需要指定null = True
4、SET_DEFAULT
将ForeignKey
设置为其默认值;必须设置ForeignKey
的默认值
官方文档- 示例 - 创建模型类 - oto/models.py
一对一【创建数据】
- 无外键的模型类[Author]:
author1 = Author.objects.create(name='XXX')
- 有外键的模型类[Wife]
wife1 = Wife.objects.create(name='YYY',author=author1)
# 关联XXXobj
wife1 = Wife.objects.create(name='YYY',author_id=1)
# 关联王老师对应主键值
一对一【查询数据】
1、正向查询:直接通关外键属性查询,则称为正向查询
2、反向查询 - 没有外键属性的一方,可以调用反向属性查询到关联的另一方
关系映射-2
一对多 - 定义
一对多是表现现实事物间存在的一对多的对应关系
如:一个学校有多个班级,一个班级有多个学生,一本图书只能属于一个出版社,一个出版社允许出版多本图书
一对多需要明确出具体角色,在多表上设置外键
一对多 - 创建
语法
当一个A类对象可以关联多个B类对象时
ForeignKey必须指定on_delete模式
示例 - 创建模型类 - otm/models.py
一对多 - 创建数据
先创建"一"在创建"多"
一对多 - 查询数据
1、正向查询[通过Book查询Publisher]
2、反向查询[通过Publisher查询对应的所有的Book]
需要用到反向属性
多对多 - 定义
多对多表达对象之间多对多复杂关系,如:每个人都有不同的学校(小学,初中,高中,......),每个学校都有不同的学生......
- mysql中创建多对多需要依赖第三张表来实现
- Django中无需手动创建第三张表,Djnago自动完成
语法:在关联的两个类中的任意一个类中,增加: - 属性 =
models.ManyToManyField(MyModel)
用法示例:
一个作者可以出版多本图书
一本图书可以被多名作者同时编写
多对多 - 创建数据
多对多 - 查询数据
1、正向查询 有多对多属性的对象 查 另一方
2、反向查询
cookies和session-1
会话定义
- 从打开浏览器访问一个网站,到关闭浏览器结束此次访问,称之为一次会话
- HTTP协议是无状态的,导致会话状态难以保持
- 试想一下,如果不保持会话状态,在电商网站购物的场景体验?
- Cookies和Session就是为了保持会话状态而诞生的两个存储技术
Cookies-定义
cookies是保存在客户端浏览器上的存储空间
Chrome浏览器可能通过开发者工具的Application >> Storage >> 'Cookies'查看和操作浏览器端所有的Cookies值
火狐浏览器可能通过开发者工具的存储 -> Cookies 查看
Cookies特点
- cookies在浏览器上是以键-值对的形式进行存储的,键和值都是以ASCII字符串的形式存储(不能是中文字符串)
- 存储的数据带有生命周期
- cookies中的数据是按域存储隔离的,不同的域之间无法访问
- cookies的内部的数据会在每次访问此网址时都会携带到服务器端,如果cookies过大会降低响应速度。
Cookies的使用 - 存储
HttpResponse.set_cookie(key,value='',max_age=None,expires=None)
-key:cookie的名字
-value:cookie的值
-max_age:cookie存活时间,秒为单位
-expires:具体过期时间
-当不指定max_age和expires时关闭浏览器时此数据失效
Cookies的使用 - 存储(续)
存储示例:
- 添加cookie
- 修改cookie
Cookies的使用 - 删除&获取
删除Cookies
-HttpResponse.delete_cookie(key)
-删除指定的key的Cookie。如果key不存在则什么也不发生
获取Cookies
-通过request.COOKIES绑定的字典(dict)获取客户端的COOKIES数据。value = request.COOKIES.get('cookies名','默认值')
- 删除cookie
- 获取cookie
cookies和session-2
session定义
session是在服务器上开辟一段空间用于保留浏览器和服务器交互时的重要数据
实现方式
-使用session需要在浏览器客户端启动cookie,且在cookie中存储sessionid。
-每个客户端都可以在服务器端有一个独立的session
-注意:不同的请求者之间不会共享这个数据,与请求者一一对应
session初始配置
settings.py
中配置session
1、向INSTALLED_APPS
列表中添加:
2、向MIDDLEWARE
列表中添加:
session的使用
Django中session是一个类似于字典的SessionStore类型的对象,可以用类拟于字典的方式进行操作。session能够存储如字符串,整型,字典,列表等。
1、保存session的值到服务器
request.session['KEY'] = VALUE
2、获取session的值
value = request.session['KEY']
value = request.session('KEY',默认值)
3、删除session
del request.session['KEY']
settings.py
中相关配置项
1、SESSION_COOKIE_AGE
作用:指定sessionid在cookies中的保存时长(默认是2周),如下:
例如:SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2
2、SESSION_EXPIRE_AT_BROWSER_CLOSE = True
设置只要浏览器关闭时,session就失效(默认为False)
注意:Django中的session数据存储在数据库中,所以使用session前需要确保已经执行过migrate
Django session的问题
1、django_session表是单表设计;且该表数据量持续增持【浏览器故意删掉sessionid & 过期数据未删除】
2、可以每晚执行python manage.py clearsessions
【该命令可删除已过期的session数据】
Cookies vs Session
缓存-1
缓存的定义
- 定义:缓存是一类可以更快的读取数据的介质统称,也指其他可以加快数据读取的存储方式。一般用来存储临时数据,常用的介质是读取速度很快的内存。
- 意义:视图渲染有一定成本,数据库的频繁查询过高;所以对于低频变动的页面可以考虑使用缓存技术,减少实际渲染次数;用户拿到响应的时间成本会更低。
- 案例分析
优化思想-转自官网
缓存场景
1、博客列表页
2、电商商品详情页
- 场景特点:缓存的地方,数据变动频率较低
缓存配置
- Django中设置缓存-数据库缓存
将缓存的数据存储在您的数据库中
说明:
尽管存储介质没有更换,但是当把一次负责查询的结果直接存储到表里,比如多个条件的过滤查询结果,可避免重复进行复杂查询,提升效率;
settings.py
中关于缓存的内容如下:
CACHES ={
'default': {
'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
'LOCATION': 'my_cache_table', #缓存存储的表名
'TIMEOUT': 60, # default to 60 seconds formation 缓存保存的时间,单位秒,默认值300
'OPTIONS':{
'Max_ENTRIES': 300, # 缓存最大数据条数
'CULL_FREQUENCY': 5, # 缓存条数达到最大值,删除1/x的缓存数据
}
}
- 数据缓存到服务器内存中
配置样例
- 将缓存的数据存储到本地文件中
配置样例
- 使用自定义缓存
尽管Django开箱即用地支持许多缓存后端,但有时可能希望使用自定义的缓存后端:要将外部缓存后端与Django一起使用。
实操流程
1、执行以下命令,创建出储存缓存的数据库表
python manage.py createcachetable
2、编辑settings.py
配置文件,详细内容在缓存配置部分已详述
整体缓存策略
- Django中使用缓存 - 视图函数中
样例
- Django中使用缓存 - 路由中
样例
缓存-2
局部缓存策略
- 缓存api的使用
先引入cache对象
方式1:使用caches['settings中CACHE中配置的key']
导入具体对象
例如:
方式2:
from django.core.cache import cache
相当于直接引入CACHES配置项中的'default'
项
调用api
1、cache.set(key,value,timeout)
- 存储缓存
key
:缓存的key,字符串类型
value
:python对象
timeout
:缓存储存时间(s),默认为CACHES
中的TIMEOUT
值
返回值:None
2、cache.get(key)
- 获取缓存
key
:缓存的key
返回值:为key的具体值,如果没有数据,则返回None
3、cache.add(key,value)
- 存储缓存,只在key不存在时生效
返回值:True[存储成功] False[存储失败]
例子:
4、cache.get_or_set(key,value,timeout)
- 如果未获取到数据则执行set操作
返回值:value
5、cache.set_many(dict,timeout)
- 批量缓存
dict
:key
和value
的字典
timeout
:存储时间(s)
返回值:插入不成功的key的数组
6、cache.get_many(key_list)
- 批量获取缓存数据
key_list
:包含key的数组
返回值:取到的key和value的字典
7、cache.delete(key)
- 删除key的缓存数据
返回值:None
8、cache.delete_many(key_list)
- 批量删除
返回值:None
浏览器缓存
- 浏览器缓存策略
-
强缓存
不会向服务器发送请求,直接从缓存中读取资源
1、响应头 - Expires
定义:缓存过期时间,用来指定资源到期的时间,是服务器端的具体的时间点
样例:Expires:Thu,02 Apr 2030 05:14:08 GMT
2、响应头 - Cache-Control
在HTTP/1.1中,Cache-Control主要用于控制网页缓存。比如当Cache-Control:max-age=120
代表请求创建时间后的120秒,缓存失效
说明:目前服务器都会带着这两个头同时响应给浏览器,浏览器优先使用Cache-Control -
协商缓存
强缓存中的数据一旦过期,还需要跟服务器进行通信,从而获取最新数据;
那么如果强缓存的数据是一些静态文件,大图片等?
考虑到大图片这类比较费带宽且不易变化的数据,强缓存时间到期后,浏览器会去跟服务器协商,当前缓存是否可用,如果可用,服务器不必返回数据,浏览器继续使用原来缓存的数据,如果文件不可用,则返回最新数据。
1、Last-Modified
响应头 和 If-Modified-Since
请求头
说明:
(1)Last-Modified
为文件的最近修改时间,浏览器第一次请求静态文件时,服务器如果返回Last-Modified
响应头,则代表该资源为需协商的缓存
(2)、当缓存到期后,浏览器将获取到的Last-Modified
值做为请求头If-Modified-Since
的值,与服务器发请求协商,服务端返回304响应码[响应体为空],代表缓存继续使用,200响应码代表缓存不可用[响应体为最新资源]
2、ETag
响应头和If-None-Match
请求头
说明:
(1)ETag
是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成),只要资源有变化,Etag就会重新生成;
(2)缓存到期后,浏览器将ETag
响应头的值作为If-None-Match
请求头的值,给服务器发请求协商;服务器接到请求头后,比对文件标识,不一致则认为资源不可用,返回200响应码[响应体为最新资源];可用则返回304响应码.
未完待续......
谢谢各位大佬的支持