django1
课程特点
-
学习难度大,大部分内容需要理解并记忆。
-
文件较多,易混淆。
-
学习阶段注重框架使用,工作阶段注重实现业务逻辑。
-
综合应用强,小练习少。
学习建议:
-
课前进行预习,课后进行复习,善于查看报错信息,增强自我排错能力。
-
课余时间自行搭建开发环境,为后续工作做准备。
课程划分:
-
Django01
为Django
基础应用部分; -
Django02
为Django
高级应用部分; -
DaDaBlog
为Django
综合项目。
Django介绍
-
-
虚拟环境(自行扩展)
-
安装
起源&应用
-
2005年发布,采用Python语言编写的开源web框架
-
早期的时候Django主做新闻和内容管理的
-
一个重量级的 Python Web框架,Django 配备了常用的大部分组件
-
基本配置
-
路由系统
-
原生HTML模板系统
-
视图 view
-
Model模型,数据库连接和ORM数据库管理
-
中间件
-
Cookie & Seesion
-
分页
-
数据库后台管理系统admin
-
-
Django的用途
-
网站后端开发
-
微信公众号、微信小程序等后台开发
-
-
基于HTTP/HTTPS协议的后台服务器开发
-
在线语音/图像识别服务器
-
在线第三方身份验证服务器等
-
-
在开发过程中, 当需要使用
python
的某些工具包/框架时需要联网安装比如联网安装
Django
框架sudo pip install Django
提示:使用如上命令, 会将
Django
安装到/usr/local/lib/python3.6/dist-packages
路径下问题:如果在一台电脑上,,想开发多个不同的项目,,需要用到同一个包的不同版本,,如果使用上面的命令,在同一个目录下安装或者更新,,新版本会覆盖以前的版本, 其它的项目就无法运行了。
解决方案 : 虚拟环境
作用 : 虚拟环境可以搭建独立的
python
运行环境, 使得单个项目的运行环境与其它项目互不影响。 所有的虚拟环境都位于/home/
下的隐藏目录.virtualenvs
下这里给大家举一个简单的例子,桌面上有一个word文件,我们打开修改这个文件,修改了一会之后发现还是原来的文件比较好,这个时候我想找回原来的文件就比较困难了。那么怎么办呢?就有这样一种解决方案,在修改文件之前,先复制一份,然后在副本文件里进行修改,这样即使发现修改有错,也不会影响原始文件。
虚拟环境其实就是对真实
pyhton
环境的复制,这样我们在复制的python
环境中安装包就不会影响到真实的python
环境。通过建立多个虚拟环境,在不同的虚拟环境中开发项目就实现了项目之间的隔离。创建
首先安装虚拟环境,命令如下:
sudo pip3 install virtualenv #安装虚拟环境
Copy
接下来还要安装虚拟环境扩展包,命令如下:
sudo pip3 install virtualenvwrapper
Copy
检车安装虚拟环境相关的扩展包:
安装虚拟环境包装器的目的是使用更加简单的命令来管理虚拟环境。
安装完虚拟环境后,如果提示找不到mkvirtualenv命令,须配置环境变量:
# 1、创建目录用来存放虚拟环境 mkdir $HOME/.virtualenvs
# 2、修改用户家目录下的配置文件.bashrc,添加如下内容:
sudo vim ~/.bashrc
# 虚拟环境
export VIRTUALENVWRAPPER=/usr/bin/python3
export WORKON_HOME=$HOME/.virtualenvs
export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
source /usr/local/bin/virtualenvwrapper.sh
# source ~/.local/bin/virtualenvwrapper.sh
# 3、运行 source ~/.bashrc
Copy
如果提示 "bash: /home/tarena/.local/bin/virtualenvwrapper.sh: 没有那个文件或目录"
则使用 which virtualenvwrapper.sh 查看所在路径,并且将source后面的路径 换成显示后的路径
Copy
使用
source .bashrc
命令使配置文件生效。创建
python3
虚拟环境的命令如下:mkvirtualenv 虚拟环境名称
例:
mkvirtualenv py3_Django
Copy
小总结
-
创建成功后,会自动工作在这个虚拟环境上。
-
创建虚拟环境需要联网。
-
工作在虚拟环境上,提示符最前面会出现"(虚拟环境名称)"。
-
所有的虚拟环境,都位于
/home/tarena/
下的隐藏目录.virtualenvs
下。
退出
退出的虚拟环境命令如下:
deactivate
退出虚拟环境
查看与使用
查看所有虚拟环境的命令如下:
提示:
workon
后面有个空格,再按两次tab
键。workon 两次tab健
查看虚拟环境
使用虚拟环境的命令如下:
写出名称的前部分后,可以使用
tab
键补齐workon 虚拟环境名称
例:workon py3_Django
使用
py3_Django
虚拟环境提示:注意提示符的变化
虚拟环境安装包
pip3 install Django==2.2.12
在虚拟环境中,如果想要使用一些包的话,正常安装即可。
删除
删除虚拟环境的命令如下:
rmvirtualenv 虚拟环境名称 例:先退出:deactivate 再删除:rmvirtualenv py3_Django
友情提示:
以上是在
ubuntu18.04
系统中进行操作,其他系统的后续更新。版本
https://www.djangoproject.com/download/#supported-versions
安装与卸载
-
查看已安装的版本
>>> import django >>> print(django.VERSION) (2, 2, 12, 'final', 0)
-
安装:
-
在线安装:
sudo pip3 install django # 安装django的最新版本 或 sudo pip3 install django[==版本] # 安装django的指定版本 # 如: sudo pip3 install django==2.2.12 # 安装 Django 2.2.12 版本 sudo pip3 install django==2.2.12 -i https://pypi.mirrors.ustc.edu.cn/simple/
-
离线安装:
1. 下载安装包:官网下载离线安装包,复制进虚拟机 2. 安装离线包 # 解压缩 tar -xvf Django-2.2.12.tar.gz # 进入目录 cd Django-2.2.12 # 执行安装 sudo python3 setup.py install
-
检查是否成功:
sudo pip3 freeze | grep -i "Django" Django==2.2.12 Copy
-
-
卸载:
pip3 uninstall django
Django
的开发环境:-
Django 2.2.12
支持3.5,3.6,3.7,3.8
创建工程的命令为:
django-admin startproject 工程名称
例如:想要在桌面的
code
目录中创建一个名为demo
的项目工程,可执行如下命令:cd ~/Desktop/code django-admin startproject demo
执行后,会多出一个新目录名为
demo
,此即为新创建的工程目录。Django项目的目录结构
-
示例:
$ django-admin startproject mysite1 $ tree mysite1/ mysite1/ ├── manage.py └── mysite1 ├── __init__.py ├── settings.py ├── urls.py └── wsgi.py 1 directory, 5 files
-
项目目录结构解析:
-
manage.py
-
此文件是项目管理的主程序,在开发阶段用于管理整个项目的开发运行的调式
-
manage.py
包含项目管理的子命令, 如:
-
python3 manage.py runserver
启动服务 -
python3 manage.py startapp
创建应用 -
python3 manage.py migrate
数据库迁移 -
...
-
-
-
mysite1 项目文件夹
-
项目包的主文件夹(默认与项目名称一致)
-
__init__.py
-
包初始化文件,当此项目包被导入(import)时此文件会自动运行
-
-
wsgi.py
-
WSGI 即 Web Server Gateway Interface
-
WEB服务网关接口的配置文件,仅部署项目时使用
-
-
urls.py
-
项目的主路由配置文件,所有的动态路径必须先走该文件进行匹配
-
-
settings.py
-
Django项目的配置文件, 此配置文件中的一些全局变量将为Django框架的运行传递一些参数
-
setting.py 配置文件,启动服务时自动调用,
-
此配置文件中也可以定义一些自定义的变量用于作用全局作用域的数据传递
-
-
-
settings.py
文件介绍https://docs.djangoproject.com/en/2.2/ref/settings/
公有配置
-
BASE_DIR
-
用于绑定当前项目的绝对路径(动态计算出来的), 所有文件都可以依懒此路径
-
-
DEBUG
-
用于配置Django项目的启动模式, 取值:
-
True 表示开发环境中使用
调试模式
(用于开发中) -
False 表示当前项目运行在
生产环境中
(不启用调试)
-
-
-
ALLOWED_HOSTS
-
设置允许访问到本项目的host请求头的值,取值:
-
[] 空列表,表示只有host请求头为
127.0.0.1
,localhost
能访问本项目 - DEBUG = True时生效 -
['*'],表示任何请求头的host都能访问到当前项目
-
['192.168.1.3', '127.0.0.1'] 表示只有当前两个host头的值能访问当前项目
-
注意:
-
如果要在局域网其它主机也能访问此主机,启动方式应使用如下模式:
-
-
-
python3 manage.py runserver 0.0.0.0:5000
# 指定网络设备如果内网环境下其他主机想正常访问该站点,需加`ALLOWED_HOSTS = ['内网ip']
-
-
INSTALLED_APPS
-
指定当前项目中安装的应用列表
-
-
MIDDLEWARE
-
用于注册中间件
-
-
TEMPLATES
-
用于指定模板的配置信息
-
-
DATABASES
-
用于指定数据库的配置信息
-
-
LANGUAGE_CODE
-
用于指定语言配置
-
取值:
-
英文 :
"en-us"
-
中文 :
"zh-Hans"
-
-
-
TIME_ZONE
-
用于指定当前服务器端时区
-
取值:
-
世界标准时间:
"UTC"
-
中国时区 :
"Asia/Shanghai"
-
-
-
ROOT_URLCONF
-
用于配置根级 url 配置 'mysite1.urls'
-
如:
-
ROOT_URLCONF = 'mysite1.urls'
-
-
私有配置
settings.py
中也可以添加 开发人员 自定义的配置配置建议:名字尽量个性化 - 以防覆盖掉公有配置;例如:
ALIPAY_KEY = 'xxxxxx'
注:
settings.py
中的所有配置项,都可以按需的在代码中引入此模块可以通过
from django.conf import settings
导入和使用运行开发服务器
在开发阶段,为了能够快速预览到开发的效果,
django
提供了一个纯python
编写的轻量级web服务器,仅在开发阶段使用。运行服务器命令如下:
python3 manage.py runserver ip:端口 或: python3 manage.py runserver
可以不写IP和端口,默认IP是127.0.0.1,默认端口为8000。
如果想要更换端口,则可以使用
python3 manage.py runserver 端口号
启动后可见如下信息:
在浏览器中输入网址
127.0.0.1:8000
便可看到效果。-
django
默认工作在调式Debug
模式下,如果增加、修改、删除文件,服务器会自动重启。 -
按
ctrl+c
停止服务器。
关闭服务
方法一:
在
runserver
启动终端下:-
执行
ctrl + c
可以关闭Django
服务。
方法二:
在其他终端下
-
执行
sudo lsof -i:8000
查看出Django
的 进程id
。 -
执行
kill -9
对应Django
进程id
。
启动常见问题
问题:
Error: That port is already in use
问题原因:端口已被使用,证明当前
Django
启动时,默认监听的8000
端口已被其他进程占用解决方案:
参照关闭服务方法二
URL 介绍
URL
即 **统一资源定位符**
Uniform Resource Locator-
作用:
-
用来表示互联网上某个资源的地址。
-
-
说明:
-
互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它
-
URL的一般语法格式为:
protocol :// hostname[:port] / path [?query][#fragment]
如:
http://tts.tmooc.cn/video/showVideo?menuId=657421&version=AID201908#subject
说明:
-
protocol(协议)
http:
-
http 通过 HTTP 访问该资源。 格式
HTTP://
-
https 通过安全的 HTTPS 访问该资源。 格式
HTTPS://
-
file 资源是本地计算机上的文件。格式:
file:///
-
-
hostname(主机名)
tts.tmooc.cn
-
是指存放资源的服务器的域名系统(DNS) 主机名、域名 或 IP 地址。
-
-
port(端口号)
80
-
整数,可选,省略时使用方案的默认端口;
-
各种传输协议都有默认的端口号,如
http
的默认端口为80。
-
-
path(路由地址)
video/showVideo
-
由零或多个
"/"
符号隔开的字符串,一般用来表示主机上的一个目录或文件地址。路由地址决定了服务器端如何处理这个请求
-
-
query (查询)
?menuId=757421&version=AID999
-
可选,用于给动态网页传递参数,可有多个参数,用
"&"
符号隔开,每个参数的名和值用"="
符号隔开。
-
-
fragment(信息片断)
#subject
-
字符串,用于指定网络资源中的片断。例如一个网页中有多个名词解释,可使用
fragment
直接定位到某一名词解释。注:
[]
代表其中的内容可省略测试markdown样式
-
浏览器
http://127.0.0.1:8000/page/2005/
-
Django 从配置文件中 根据 ROOT_URLCONF 找到 主路由文件;默认情况下,该文件在 项目同名目录下的urls; 例如
mysite1/mysite1/urls.py
-
Django 加载 主路由文件中的
urlpatterns
变量 -
依次匹配
urlpatterns
中的 URL, 匹配到第一个合适的中断后续匹配 -
匹配成功
- 调用对应的视图函数处理请求,返回响应 -
匹配失败
- 返回404响应
# 主路由-urls.py样例 from django.urls import path from . import views urlpatterns = [ path('admin/', admin.site.urls) path('page/2003/', views.page_2003), path('page/2004/', views.page_2004), ]
##
视函数使用
视图函数是用于接收一个浏览器请求并通过
HttpResponse
对象返回数据的函数。此函数可以接收浏览器请求并根据业务逻辑返回相应的内容给浏览器。视图处理的函数的语法格式:
def xxx_view(request[, 其它参数...]): return HttpResponse对象 Copy
参数:
-
request
用于绑定HttpRequest
对象,通过此对象可以获取浏览器的参数和数据
返回值
HttpResponse
的对象;Django
会提供一系列的response
对象;试图函数示例:
视图处理函数
views.py
# file : <项目同名文件夹下>/views.py from django.http import HttpResponse def page1_view(request): html = "<h1>这是第1个页面</h1>" return HttpResponse(html)
settings.py
中的ROOT_URLCONF
指定了主路由配置列表urlpatterns
的文件位置urls.py 主路由配置文件
# file : <项目同名文件夹>/urls.py urlpatterns = [ path('admin/', admin.site.urls), ... # 此处配置主路由 ] Copy
path() 函数
用于描述路由与视图函数的对应关系
-
模块
-
from django.urls import path
-
-
语法:
path(route, views, name=None) 参数: 1. route: 字符串类型,匹配的请求路径 2. views: 指定路径所对应的视图处理函数的名称 3. name: 为地址起别名,在模板中地址反向解析时使用 Copy
练习
-
建立一个小网站:
-
输入网址:
-
输入网址: http://127.0.0.1:8000/page/1, 在网页中输出 : 这是编号为1的网页
-
输入网址: http://127.0.0.1:8000/page/2, 在网页中输出 : 这是编号为2的网页
-
-
思考
-
建立如上一百个网页该怎么办?
-
path转换器
语法:
<转换器类型:自定义名>
作用:若转换器类型匹配到对应类型的数据,则将数据按照关键字传参的方式传递给视图函数
示例:
path('page/<int:age>', views.xxx)
转换器 效果 案例 str
匹配除了 '/'
之外的非空字符串"v1/users/\<str:username>"
匹配/v1/users/xiaohanghang
int
匹配0或任何正整数。返回一个 int "page/\<int:page>"
匹配/page/100
slug
匹配任意由 ASCII 字母或数字以及连字符和下划线组成的短标签 "detail/\<slug:sl>"
匹配/detail/this-is-django
path
匹配非空字段,包括路径分隔符 '/'
"v1/users/\<path:ph>"
匹配/v1/goods/a/b/c
练习:小计算器
-
定义一个路由的格式为:
-
http://127.0.0.1:8000/整数/操作字符串/整数
-
-
从路由中提取数据,做相应的操作后返回给浏览器
-
如:
输入: 127.0.0.1:8000/100/add/200 页面显示结果:300 输入: 127.0.0.1:8000/100/sub/200 页面显示结果:-100 输入: 127.0.0.1:8000/100/mul/200 页面显示结果:20000 Copy
re_path()函数
-
在
url
的匹配过程中可以使用正则表达式进行精确匹配 -
语法:
-
re_path(reg, view, name=xxx)
-
正则表达式为命名分组模式
(?P<name>pattern)
;匹配提取参数后用关键字传参方式传递给视图函数
-
示例:
-
路由配置文件
# file : <项目同名文件夹>/urls.py # 以下示例匹配 # 可匹配 http://127.0.0.1:8000/20/mul/40 # 不可匹配 http://127.0.0.1:8000/200/mul/400 urlpatterns = [ path('admin/', admin.site.urls), re_path(r'^(?P<x>\d{1,2})/(?P<op>\w+)/(?P<y>\d{1,2})$',views.cal_view), ] Copy
练习:
-
访问地址:
-
http://127.0.0.1:8000/birthday/四位数字/一到两位数字/一到两位数字
-
http://127.0.0.1:8000/birthday/一到两位数字/一到两位数字/四位数字
-
-
最终输出: 生日为: xxxx年xx月xx日
-
如:
输入网址: http://127.0.0.1:8000/birthday/2015/12/11 显示为: 生日为:2015年12月11日 输入网址: http://127.0.0.1:8000/birthday/2/28/2008 显示为: 生日为:2008年2月28日 Copy
HTTP协议的请求和响应
-
请求是指浏览器端通过HTTP协议发送给服务器端的数据
-
响应是指服务器端接收到请求后做相应的处理后再回复给浏览器端的数据
请求
请求样式
请求中的方法
-
根据
HTTP
标准,HTTP请求可以使用多种请求方法。 -
HTTP1.0
定义了三种请求方法: GET, POST 和 HEAD方法(最常用) -
HTTP1.1
新增了五种请求方法:OPTIONS
,PUT
,DELETE
,TRACE
和CONNECT
方法。 -
HTTP1.1
请求详述
序号 方法 描述 1 GET 请求指定的页面信息,并返回实体主体。 2 HEAD 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头 3 POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。 4 PUT 从客户端向服务器传送的数据取代指定的文档的内容。 5 DELETE 请求服务器删除指定的页面。 6 CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。 7 OPTIONS 允许客户端查看服务器的性能。 8 TRACE 回显服务器收到的请求,主要用于测试或诊断。 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.get_host()
: 请求的主机 -
request.META Copy
: 请求中的元数据(消息头)
-
request.META['REMOTE_ADDR']
: 客户端IP地址
-
响应
当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求。当浏览器接收并显示网页前,此网页所在的服务器会返回一个包含HTTP状态码的信息头用以响应浏览器的请求。
响应样式
响应状态码
-
HTTP
状态码的英文为HTTP Status Code
。 -
下面是常见的HTTP状态码:
-
200 - 请求成功
-
301 - 永久重定向-资源(网页等)被永久转移到其它URL
-
302 - 临时重定向
-
404 - 请求的资源(网页等)不存在
-
500 - 内部服务器错误
-
-
HTTP状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字没有分类的作用。HTTP状态码共分为5种类型:
分类 分类描述 1** 信息,服务器收到请求,需要请求者继续执行操作 2** 成功,操作被成功接收并处理 3** 重定向,需要进一步的操作以完成请求 4** 客户端错误,请求包含语法错误或无法完成请求 5** 服务器错误,服务器在处理请求的过程中发生了错误 Django 中的响应对象
HttpResponse 对象
构造函数格式:
-
HttpResponse(content=响应体, content_type=响应体数据类型, status=状态码)
作用:
-
向客户端浏览器返回响应,同时携带响应体内容
参数:
-
content
:表示返回的内容。 -
status_code
:返回的HTTP响应状态码(默认为200)。 -
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文件)注: 关键字MIME(Multipurpose Internet Mail Extensions)是指多用途互联网邮件扩展类型。
-
HttpResponse 子类
类型 作用 状态码 HttpResponseRedirect
重定向 302 HttpResponseNotModified
未修改 304 HttpResponseBadRequest
错误请求 400 HttpResponseNotFound
没有对应的资源 404 HttpResponseForbidden
请求被禁止 403 HttpResponseServerError
服务器错误 500 -
-
-
Django处理GET和POST请求
-
无论是
GET
还是POST
,统一都由视图函数接收请求,通过判断request.method
区分具体的请求动作 -
样例:
if request.method == 'GET': 处理GET请求时的业务逻辑 elif request.method == 'POST': 处理POST请求的业务逻辑 else: 其他请求业务逻辑 Copy
Django 中GET 处理
GET 请求
-
GET请求动作,一般用于向服务器获取数据
-
能够产生GET请求的场景:
-
浏览器地址栏中输入URL,回车后
-
<a href="地址?参数=值&参数=值">
-
form
表单中的method
为get
<form method='get' action="/user/login"> 姓名:<input type="text" name="uname"> </form> Copy
-
-
GET请求方式中,如果有数据需要传递给服务器,通常会用查询字符串(
Query String
)传递 【注意:不要传递敏感数据】-
URL 格式:
xxx?参数名1=值1&参数名2=值2...
-
如:
http://127.0.0.1:8000/page1?a=100&b=200
-
-
服务器端接收参数
获取客户端请求GET请求提交的数据
-
方法示例
request.GET['参数名'] # QueryDict request.GET.get('参数名','默认值') request.GET.getlist('参数名') # mypage?a=100&b=200&c=300&b=400 # request.GET=QueryDict({'a':['100'], 'b':['200','400'], 'c':['300']}) # a = request.GET['a'] # b = request.GET['b'] # Error Copy
思考:之前的计算器功能,能否拿查询字符串做?
Django中处理POST请求
POST 请求
-
POST
请求动作,一般用于向服务器提交大量数据/隐私数据 -
客户端通过表单等
POST
请求将数据传递给服务器端,如:<form method='post' action="/login"> 姓名:<input type="text" name="username"> <input type='submit' value='登陆'> </form> Copy
服务器端接收参数
通过request.method
来判断是否为POST
请求,如:
if request.method == 'POST': 处理POST请求的数据并响应 else: 处理非POST 请求的响应
使用post方式接收客户端数据
request.POST['参数名'] # request.POST 绑定QueryDict request.POST.get('参数名','') request.POST.getlist('参数名')
取消 csrf 验证
-
取消
csrf
验证,否则Django
将会拒绝客户端发来的POST
请求,报403
响应 -
禁止掉
settings.py
中MIDDLEWARE
中的CsrfViewsMiddleWare
的中间件MIDDLEWARE = [ ... # 'django.middleware.csrf.CsrfViewMiddleware', ... ]
Django框架设计模式
传统的MVC
MVC代表Model-View-Controller(模型-视图-控制器)模式。
-
M模型层(Model), 主要用于对数据库层的封装
-
V视图层(View),用于向用户展示结果(WHAT + HOW)
-
C 控制(Controller ,用于处理请求、获取数据、返回结果(重要)
作用:降低模块间的耦合度(解耦)
Django中的MTV模式
MTV代表模型-模板-视图(模型-模板-视图)模式。
-
M 模型层(Model) 负责与数据库交互
-
T模板层(Template) 形象地展示内容到浏览器 (HOW)
-
V视图层(View)是核心,负责接收请求、获取数据、返回结果(WHAT)
作用:降低模块间的耦合度(解耦)
MTV-诞生记
模板
什么是模板?
-
模板是可以根据字典数据动态变化的
html
网页 -
模板可以根据视图中传递的字典数据动态生成相应的
html
网页。
创建模板文件夹 <项目名>/templates
在 settings.py
中 TEMPLATES
配置项
-
BACKEND
: 指定模板的引擎 -
DIRS
: 模板的搜索目录(可以是一个或多个) -
APP_DIRS
: 是否要在应用中的templates
文件夹中搜索模板文件 -
OPTIONS
: 有关模板的选项 -
配置项中 需要修改部分
设置
DIRS - 'DIRS': [os.path.join(BASE_DIR, 'templates')],
# file: settings.py TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', # 'DIRS': [], 'DIRS': [os.path.join(BASE_DIR, 'templates')], # 添加模板路径 'APP_DIRS': True, # 是否索引各app里的templates目录 ... }, ]
模板的加载方式
方案一
通过 loader
获取模板,通过HttpResponse
进行响应
在视图函数中
from django.template inport loader # 1. 通过 loader 加载模板 t = loader.get_template("模板文件名") # 2. 将 t 转换成 HTML 字符串 html = t.render(字典数据) # 3. 用响应对象将转换的字符串内容返回给浏览器 return HttpResponse(html) Copy
方案二
使用 render()
直接加载并响应模板
在视图函数中:
from django.shortcuts import render return render(request, '模板文件名', 字典数据) Copy
试图层与模板层之间的交互
-
视图函数中可以将Python变量封装到字典中传递到模板 样例:
def xxx_view(request): dic = { "变量1":"值1", "变量2":"值2", } return render(request, "xxx.html", dic) Copy
-
模板中, 我们可以用
{}
的语法 调用视图传进来的变量
模板的变量
模板的变量
视图函数中可以将Python
变量封装到 字典
中传递到模板上
样例:
def xxx_view(request): dic = { "变量1":"值1", "变量2":"值2", } return render(request, "xxx.html", dic) Copy
模板中使用变量的方法
{{ 变量名 }} {{ 变量名.index }} {{ 变量名.key}} {{ 对象.方法 }} {{ 函数名 }} Copy
能够传递到模板中的数据类型:
-
str
- 字符串int
- 整型 -
list
- 数组tuple
- 元组 -
dict
- 字典func
- 方法 -
obj
- 类实例化的对象
模板的标签
作用:将一些服务器端的功能嵌入到模板中,例如流程控制等
标签语法
{% 标签 %} ... {% 结束标签 %} Copy
模板标签 - if标签
{% if 条件表达式1 %} ... {% elif 条件表达式2 %} ... {% elif 条件表达式3 %} ... {% else %} ... {% endif %} Copy
注意:
if
条件表达式里可以用的运算符==, !=, <, >, <=, >=, in, not in, is, is not, not、and、or
在
if
标记中使用实际括号是无效的语法。 如果您需要它们指示优先级,则应使用嵌套的if
标记。官方文档:https://docs.djangoproject.com/zh-hans/2.2/ref/templates/builtins/#if
模板标签 - if标签 - 练习
写一个简单的计算器页面,能够在服务端进行简单加减乘除计算
= 3
<form action='/mycal' method='post'> <input type='text' name="x" value="1"> <select name='op'> <option value="add"> +加 </option> <option value="sub"> -减 </option> <option value="mul"> *乘 </option> <option value="div"> /除 </option> </select> <input type='text' name="y" value="2"> = <span>3</span> <div> <input type="submit" value='开始计算'> </div> </form> Copy
模板标签 - for标签
语法:
{% for 变量 in 可迭代对象 %} ... 循环语句 {% empty %} ... 可迭代对象无数据时填充的语句 {% endfor %} Copy
官方文档:https://docs.djangoproject.com/en/2.2/ref/templates/builtins/#for
内置变量 - forloop
变量 | 描述 |
---|---|
forloop.counter | 循环的当前迭代(从1开始索引) |
forloop.counter0 | 循环的当前迭代(从0开始索引) |
forloop.revcounter | counter值得倒序 |
forloop.revcounter0 | revcounter值的倒序 |
forloop.first | 如果这是第一次通过循环,则为真 |
forloop.last | 如果这是最后一次循环,则为真 |
forloop.parentloop | 当嵌套循环,parentloop 表示外层循环 |
模板的过滤器
模板层 — 过滤器
定义:在变量输出时对变量的值进行处理
作用:可以通过使用 过滤器来改变变量的输出显示
语法:{{ 变量 | 过滤器1:'参数值1' | 过滤器2:'参数值2' ... }}
常用过滤器
过滤器 | 说明 |
---|---|
lower |
将字符串转换为全部小写。 |
upper |
将字符串转换为大写形式 |
safe |
默认不对变量内的字符串进行html转义 |
add: "n" |
将value的值增加 n |
truncatechars:'n' |
如果字符串字符多于指定的字符数量,那么会被截断。 截断的字符串将以可翻译的省略号序列(“...”)结尾。 |
官方文档:https://docs.djangoproject.com/en/2.2/ref/templates/builtins/
模板的继承
请看如下样式:
模板继承可以使父模板的内容重用,子模板直接继承父模板的全部内容并可以覆盖父模板中相应的块
语法 - 父模板中:
-
定义父模板中的块
block
标签 -
标识出哪些在子模块中是允许被修改的
-
block
标签:在父模板中定义,可以在子模板中覆盖
语法 - 子模板中
继承模板 extends
标签(写在模板文件的第一行)
-
例如:
子模板 重写父模板中的内容块
{% block block_name %} 定义模板块,此模板块可以被子模板重新定义的同名块覆盖 {% endblock block_name %} Copy
重写的覆盖规则
不重写,将按照父模板的效果显示
重写,则按照重写效果显示
注意
模板继承时,服务器端的动态内容无法继承
参考文档:https://docs.djangoproject.com/en/2.2/ref/templates/language/#for-template-blocks
URL反向解析
再谈 url
代码中 url 出现位置
-
模板【html中】
1. <a href='url'>超链接</a> 点击后 页面跳转至 url 2. <form action='url' method='post'> form表单中的数据 用post方法提交至 url Copy
-
视图函数中 - 302跳转
HttpResponseRedirect('url')
-
将用户地址栏中的地址跳转到
url
-
代码中 url 书写规范
-
相对地址
-
'/page/1'
-‘/’
开头的相对地址,浏览器会把当前地址栏里的 协议,ip和端口加上这个地址,作为最终访问地址, 即如果当前页面地址栏为 http://127.0.0.1:8000/page/3; 当前相对地址最终结果为 -
'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', views.page_view, name="page_url") Copy
根据path
中的name=
关键字传参给 url
确定了个唯一确定的名字,在模板或视图中,可以通过这个名字反向推断出此url
信息
模板中
-
通过
url 标签
实现地址的反向解析 -
在视图函数中 ->可调用
django
中的reverse
方法进行反向解析from django.urls import reverse reverse('别名', args=[], kwargs={}) eg: print(reverse('pagen',args=[300])) print(reverse('person',kwargs={'name':'xixi','age':18})) Copy
静态文件
什么是静态文件
-
如:图片,css,js,音频,视频
静态文件配置
-
在
settings.py
中配置一下两项内容: -
配置静态文件的访问路径
-
通过哪个
url
地址找静态文件 -
STATIC_URL = '/static/'
-
说明:
-
指定访问静态文件时是需要通过
/static/xxx
或127.0.0.1:8000/static/xxx
-
xxx 表示具体的静态资源位置
-
-
-
配置静态文件的存储路径
STATICFILES_DIRS
-
STATICFILES_DIRS
保存的是静态文件在服务器端的存储位置
-
-
示例:
# file: setting.py STATICFILES_DIRS = ( os.path.join(BASE_DIR, "static"), ) Copy
静态文件访问
使用静态文件的访问路径进行访问
-
访问路径:
STATIC_URL = '/static/'
-
示例:
<img src="/static/images/lena.jpg"> Copy
<img src="http://127.0.0.1:8000/static/images/lena.jpg"> Copy
通过 static 标签访问静态文件
Django中的应用
应用在Django
项目中是一个独立的业务模块,可以包含自己的路由,视图,模板,模型
创建应用app
步骤1
用manage.py
中的子命令 startapp
创建应用文件夹
python3 manage.py startapp music Copy
步骤2
在settings.py
的 INSTALLED_APPS
列表中配置安装此应用
INSTALLED_APPS = [ # .... 'user', #用户信息模块 'music', #音乐模块 ] Copy
应用目录结构
-
migrations 文件夹
-
保存数据迁移的中间文件
-
-
__init__.py
-
应用子包的初始化文件
-
-
admin.py
-
应用的后台管理配置文件
-
-
apps.py
-
应用的属性配置文件
-
-
models.py
-
与数据库相关的模型映射类文件
-
-
tests.py
-
应用的单元测试文件
-
-
views.py
-
定义视图处理函数的文件
应用的分布式路由
Django中,主路由配置文件(
urls.py
)可以不处理用户具体路由,主路由配置文件的可以做请求的分发(分布式请求处理)。具体的请求可以由各自的应用来进行处理 -
配置分布式路由
步骤一 : 主路由中调用 include 函数
语法:include('app名字.url模块名')
作用:用于将当前路由转到各个应用的路由配置文件的 urlpatterns
进行分布式处理
以http://127.0.0.1:8000/music/index 为例:
from django.urls import path, include from . import views urlpatterns = [ path('admin/', admin.site.urls), path('test_static/', views.test_static), path('music/', include('music.urls')), ] Copy
步骤2 : 应用下配置urls.py
应用下手动创建urls.py
文件
内容结构同主路由完全一样
from django.urls import path, include from . import views urlpatterns = [ # http:127.0.0.0:8000/music/index path('index', views.index_view), ] Copy
练习:配置分布式路由
1.创建两个应用 1.创建 sport 应用,并注册 2.创建 news 应用,并注册 2.创建分布式路由系统 1. http://127.0.0.1:8000/sport/index 交给 sport 应用中的 index_view() 函数处理 2. http://127.0.0.1:8000/news/index 交给 news 应用中的 index_view() 函数处理 Copy
应用下的模板
应用内部可以配置模板目录
-
应用下手动创建
templates
文件夹 -
settings.py
中 开启 应用模板功能TEMPLATES
配置项中 的 'APP_DIRS
' 值 为True
即可
应用下templates 和 外层templates 都存在时,django得查找模板规则
-
优先查找外层
templates
目录下的模板 -
按
INSTALLED_APPS
配置下的 应用顺序 逐层查找
模型层及ORM介绍
Django 中配置使用 mysql 数据库
安装
-
安装
mysqlclient
[版本 mysqlclient 1.3.13以上 ,官网目前为1.4.x] -
安装前确认ubuntu是否已安装
python3-dev
和
default-libmysqlclient-dev
-
sudo apt list --installed|grep -E 'libmysqlclient-dev|python3-dev'
-
若命令无输出则需要安装 -
sudo apt-get install python3-dev default-libmysqlclient-dev
-
-
sudo pip3 install mysqlclient
创建数据库
1. 进入mysql数据库 执行
-
create database 数据库名 default charset utf8
-
通常数据库名跟项目名保持一致
create database mysite1 default charset utf8 collate utf8_general_ci; Copy
2. settings.py 里进行数据库的配置
-
修改
DATABASES
配置项的内容, 由sqlite3
变为mysql
-
DATABASE
配置样例-
sqlite
数据库配置
# file: settings.py DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } Copy
-
mysql
数据库配置
DATABASES = { 'default' : { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'mywebdb', # 数据库名称,需要自己定义 'USER': 'root', 'PASSWORD': '123456', # 管理员密码 'HOST': '127.0.0.1', 'PORT': 3306, } } Copy
-
关于数据为的SETTING设置
-
ENGINE
-
指定数据库存储引擎
'django.db.backends.mysql' 'django.db.backends.sqlite3' 'django.db.backends.oracle' 'django.db.backends.postgresql' Copy
-
-
NAME
-
指定要连接的数据库的名称
-
'NAME': 'mywebdb'
-
-
USER
-
指定登录到数据库的用户名
-
'USER':'root'
-
-
PASSWORD
-
接数据库的密码。
-
'PASSWORD':'123456'
-
-
HOST
-
连接数据库时使用哪个主机。
-
'HOST':'127.0.0.1'
-
-
PORT
-
连接数据库时使用的端口。
-
'PORT':'3306'
-
模型Models
什么是模型
-
模型是一个
Python
类,它是由django.db.models.Model
派生出的子类。 -
一个模型类代表数据库中的一张数据表
-
模型类中每一个类属性都代表数据库中的一个字段。
-
模型是数据交互的接口,是表示和操作数据库的方法和方式
Django的ORM框架
定义:
ORM(Object Relational Mapping)即对象关系映射,它是一种程序技术,它允许你使用类和对象对数据库进行操作,从而避免通过SQL语句操作数据库
作用:
-
建立模型类和表之间的对应关系,允许我们通过面向对象的方式来操作数据库。
-
根据设计的模型类生成数据库中的表格。
-
通过简单的配置就可以进行数据库的切换。
优点:
只需要面向对象编程, 不需要面向数据库编写代码.
-
对数据库的操作都转化成对类属性和方法的操作.
-
不用编写各种数据库的sql语句.
实现了数据模型与数据库的解耦, 屏蔽了不同数据库操作上的差异.
-
不在关注用的是mysql、oracle...等数据库的内部细节.
-
通过简单的配置就可以轻松更换数据库, 而不需要修改代码
缺点
-
对于复杂业务,使用成本较高
-
根据对象的操作转换成SQL语句,根据查询的结果转化成对象, 在映射过程中有性能损失.
映射图
模型示例
此示例为添加一个 bookstore_book 数据表来存放图书馆中书目信息
-
添加一个
bookstore
的app
python3 manage.py startapp bookstore
-
添加模型类并注册
app
# 模型类代码示例 # file : bookstore/models.py from django.db import models class Book(models.Model): title = models.CharField("书名", max_length=50, default='') price = models.DecimalField('定价', max_digits=7, decimal_places=2, default=0.0) Copy
# 注册app # file : setting.py INSTALLED_APPS = [ ... 'bookstore', ] Copy
-
数据库迁移
-
迁移是Django同步您对模型所做更改(添加字段,删除模型等) 到您的数据库模式的方式
-
生成或更新迁移文件
将每个应用下的models.py文件生成一个中间文件,并保存在migrations文件夹中
python3 manage.py makemigrations
-
执行迁移脚本程序
执行迁移程序实现迁移。将每个应用下的migrations目录中的中间文件同步回数据库
python3 manage.py migrate
注: 每次修改完模型类再对服务程序运行之前都需要做以上两步迁移操作。
-
-
模型类需继承自django.db.models.Model
Models的语法规范
from django.db import models class 模型类名(models.Model): 字段名 = models.字段类型(字段选项) Copy
-
模型类的类名是数据表名的一部分,建议类名首字母大写
-
类属性名,此名称将作为数据表的字段名
-
字段类型用来映射到数据表中的字段的类型
-
字段选项为这些字段提供附加的参数信息
创建模型类流程
-
创建应用
-
在应用下的
models.py
中编写模型类from django.db import models class 模型类名(models.Model): 字段名 = models.字段类型(字段选项) Copy
-
迁移同步
makemigrations & migrate
任何关于表结构的修改,务必在对应模型类上修改
例:为
bookstore_book
表 添加一个 名为info
的字段varchar(100)
解决方案 ->
模型类中添加 对应 类属性
执行数据库迁移
字符类型
-
BooleanField()
-
数据库类型:
tinyint(1)
-
编程语言中:使用True或False来表示值
-
在数据库中:使用1或0来表示具体的值
-
-
CharField()
-
数据库类型:
varchar
-
注意:
-
必须要指定
max_length
参数值
-
-
-
DateField()
-
数据库类型:
date
-
作用:表示日期
-
参数:
-
auto_now
: 每次保存对象时,自动设置该字段为当前时间(取值:True/False)。 -
auto_now_add
: 当对象第一次被创建时自动设置当前时间(取值:True/False)。 -
default
: 设置当前时间(取值:字符串格式时间如: '2019-6-1')。 -
以上三个参数只能多选一
-
-
-
DateTimeField()
-
数据库类型:
datetime(6)
-
作用:表示日期和时间
-
参数同
DateField
-
-
DecimalField()
-
数据库类型:
decimal(x,y)
-
编程语言中:使用小数表示该列的值
-
在数据库中:使用小数
-
参数:
-
max_digits
: 位数总数,包括小数点后的位数。 该值必须大于等于decimal_places
. -
decimal_places
: 小数点后的数字数量
-
-
示例:
money=models.DecimalField( max_digits=7, decimal_places=2, default=0.0 ) Copy
-
-
FloatField()
-
数据库类型:
double
-
编程语言中和数据库中都使用小数表示值
-
-
EmailField()
-
数据库类型:
varchar
-
编程语言和数据库中使用字符串
-
-
IntegerField()
-
数据库类型:
int
-
编程语言和数据库中使用整数
-
-
URLField()
-
数据库类型:
varchar(200)
-
编程语言和数据库中使用字符串
-
-
ImageField()
-
数据库类型:
varchar(100)
-
作用:在数据库中为了保存图片的路径
-
编程语言和数据库中使用字符串
-
-
TextField()
-
数据库类型:
longtext
-
作用:表示不定长的字符数据
-
参考文档 https://docs.djangoproject.com/en/2.2/ref/models/fields/#field-types
创建模型类
在 bookstore/models.py
应用中 添加 一个模型类
Author - 作者
-
name - CharField 姓名 长度最大11
-
age - IntergerField 年龄
-
email - EmailField 邮箱
字段选项
-
字段选项, 指定创建的列的额外的信息
-
允许出现多个字段选项,多个选项之间使用,隔开
-
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界面上的显示名称。
-
-
示例:
# 创建一个属性,表示用户名称,长度30个字符,必须是唯一的,不能为空,添加索引 name = models.CharField(max_length=30, unique=True, null=False, db_index=True) Copy
文档参见:https://docs.djangoproject.com/en/2.2/ref/models/fields/#field-options
好习惯: 修改过 字段选项 【添加或更改】均要执行
makemigrations & migrate
Meta内部类
-
使用内部
Meta类
来给模型赋予属性,Meta类
下有很多内建的类属性,可对模型类做一些控制 -
示例:
# file : bookstore/models.py from django.db import models class Book(models.Model): title = models.CharField("书名", max_length=50, default='') price = models.DecimalField('定价', max_digits=7, decimal_places=2, default=0.0) class Meta: db_table = 'book' #可改变当前模型类对应的表名 Copy
修改模型类
1. 模型类 - Book 表名 book title - CharField(50) - 书名 唯一 pub - CharField(100) - 出版社 非空 price - DecimalField - 图书定价 总位7/小数点2位 market_price - 图书零售价 总位7/小数点2位 2. 模型类 - Author 表名 author name - CharField(11) - 姓名 非空 age - IntegerField - 年龄 默认值为1 email - EmailField - 邮箱 允许为空 Copy
数据库的迁移错误处理方法
当执行 $ python3 manage.py makemigrations
出现如下迁移错误时的处理方法
-
错误信息
You are trying to add a non-nullable field 'des' to book without a default; we can't do that (the database needs something to populate existing rows). Please select a fix: 1) Provide a one-off default now (will be set on all existing rows with a null value for this column) 2) Quit, and let me add a default in models.py Select an option: Copy
-
翻译为中文如下:
您试图添加一个非空字段'des'来预订没有默认;我们不能这样做(数据库需要填充现有行) 请选择修复: 1)现在提供一次性默认值(将对所有现有行设置此列的空值) 2)退出,让我在models.py中添加一个默认值 选择一个选项: Copy
-
错误原因
-
当对模型类新添加一个字段时可出现该错误
-
原理是 添加新字段后,数据库不知道原来已有数据对于新建字段该如何赋值,所以新增字段时,务必要添加
default
默认值。
-
-
处理方法:
-
选择1 则会进入到
shell
中,手动输入一个默认值 -
退出当前生成迁移文件的过程,自己去修改models.py, 新增加一个
default=XXX
的缺省值(推荐使用)
-
-
数据库的迁移文件混乱的解决办法
-
删除 所有
migrations
里所有的000?*XXXX.py
(__init__.py
除外) -
删除 数据库
-
sql>
drop database mywebdb;
-
-
重新创建 数据库
-
sql>
create datebase mywebdb default charset...;
-
-
重新生成migrations里所有的 000?_XXXX.py
-
python3 manage.py makemigrations
-
-
重新更新数据库
-
python3 manage.py migrate
-
-
数据库的基本操作
-
基本操作包括增删改查操作,即(
CRUD
操作) -
CRUD
是指在做计算处理时的增加(Create
)、读取查询(Read
)、更新(Update
)和删除(Delete
)
ORM CRUD 核心 -> 模型类.管理器对象
管理器对象
-
每个继承自
models.Model
的模型类,都会有一个objects
对象被同样继承下来。这个对象叫管理器对象 -
数据库的增删改查可以通过模型的管理器实现
class MyModel(models.Model): ... MyModel.objects.create(...) # objects 是管理器对象 Copy
Django Shell
-
在
Django
提供了一个交互式的操作项目叫Django Shell
它能够在交互模式用项目工程的代码执行相应的操作 -
利用
Django Shell
可以代替编写View
的代码来进行直接操作 -
在
Django Shell
下只能进行简单的操作,不能运行远程调式 -
启动方式:
$ python3 manage.py shell Copy
增加操作
-
Django
使用一种直观的方式把数据库表中的数据表示成Python
对象 -
创建数据中每一条记录就是创建一个数据对象
-
MyModel.objects.create(属性1=值1, 属性2=值1,...)
-
成功: 返回创建好的实体对象
-
失败: 抛出异常
-
-
创建
MyModel
实例对象,并调用save()
进行保存obj = MyModel(属性=值,属性=值) obj.属性 = 值 obj.save() Copy
-
练习
在 bookstore/models.py 应用中添加两个model类 1. Book - 图书 1. title - CharField 书名,非空,唯一 2. pub - CharField 出版社,字符串,非空 3. price - DecimalField 图书定价 总长6位/小数点2位 4. market_price - 图书零售价 总长6位/小数点2位 2. Author - 作者 1. name - CharField 姓名,非空 2. age - IntegerField, 年龄,非空,缺省值为1 3. email - EmailField, 邮箱,允许为空 Copy
然后用Django Shell
添加如下数据
图书信息
书名 | 定价 | 零售价 | 出版社 |
---|---|---|---|
Python | 20.00 | 25.00 | 清华大学出版社 |
Django | 70.00 | 75.00 | 清华大学出版社 |
JQuery | 90.00 | 85.00 | 机械工业出版社 |
Linux | 80.00 | 65.00 | 机械工业出版社 |
HTML5 | 90.00 | 105.00 | 清华大学出版社 |
作者信息:
姓名 | 年龄 | 性别 |
---|---|---|
王老师 | 28 | |
吕老师 | 31 | |
祁老师 | 30 |
查询操作
数据库的查询需要使用 管理器对象 进行
通过 MyModel.objects
管理器方法调用查询方法
方法 | 说明 |
---|---|
all() | 查询全部记录,返回QuerySet查询对象 |
get() | 查询符合条件的单一记录 |
filter() | 查询符合条件的多条记录 |
exclude() | 查询符合条件之外的全部记录 |
... |
查询方法
1. all()方法
-
方法:
all()
-
用法:
MyModel.objects.all()
-
作用: 查询
MyModel
实体中所有的数据 -
等同于
select * from tabel
-
返回值:
QuerySet
容器对象,内部存放MyModel
实例 -
示例:
from bookstore.models import Book books = Book.objects.all() for book in books: print("书名", book.title, '出版社:', book.pub) Copy
在模型类中定义 def __str__(self):
方法可以自定义默认的字符串
class Book(models.Model): title = ... def __str__(self): return "书名: %s, 出版社: %s, 定价: %s" % (self.title, self.pub, self.price) Copy
2. 查询返回指定列(字典表示)
-
方法:
values('列1', '列2')
-
用法:
MyModel.objects.values(...)
-
作用: 查询部分列的数据并返回
-
select 列1,列2 from xxx
-
-
返回值:
QuerySet
-
返回查询结果容器,容器内存字典,每个字典代表一条数据,
-
格式为:
{'列1': 值1, '列2': 值2}
-
-
示例:
from bookstore.models import Book books = Book.objects.values("title", "pub") for book in books: print("书名", book["title"], '出版社:', book['pub']) print("book=", book) Copy
3. 查询返回指定列(元组表示)
-
方法:
values_list('列1','列2')
-
用法:
MyModel.objects.values_list(...)
-
作用: 返回元组形式的查询结果
-
返回值:
QuerySet
容器对象,内部存放元组
-
会将查询出来的数据封装到元组中,再封装到查询集合
QuerySet
中
-
-
示例:
from bookstore.models import Book books = Book.objects.values_list("title", "pub") for book in books: print("书名", book[0], '出版社:', book[1]) print("book=", book) # ('Python', '清华大学出版社')... Copy
4. 排序查询
-
方法:
order_by
-
用法:
MyModel.objects.order_by('-列','列')
-
作用:
-
与
all()
方法不同,它会用SQL 语句的ORDER BY 子句
对查询结果进行根据某个字段选择性的进行排序
-
-
说明:
-
默认是按照升序排序,降序排序则需要在列前增加'-'表示
-
示例:
from bookstore.models import Book books = Book.objects.order_by("price") for book in books: print("书名:", book.title, '定价:', book.price) Copy
练习
制作 ‘查看所有书籍’的页面
视图函数 all_book
url
http://127.0.0.1:8000/bookstore/all_book
5. 条件查询 - filter
-
方法:
filter(条件)
-
语法:
MyModel.objects.filter(属性1=值1, 属性2=值2) Copy
-
返回值:
-
QuerySet
容器对象,内部存放MyModel
实例
-
-
说明:
-
当多个属性在一起时为"与"关系,即当
Books.objects.filter(price=20, pub="清华大学出版社")
返回定价为20且
出版社为"清华大学出版社"的全部图书
-
-
示例:
# 查询书中出版社为"清华大学出版社"的图书 from bookstore.models import Book books = Book.objects.filter(pub="清华大学出版社") for book in books: print("书名:", book.title) # 查询Author实体中name为王老师并且age是28岁的 authors=Author.objects.filter(name='王老师',age=28) Copy
6. 条件查询 - exclude
-
方法:
exclude(条件)
-
语法:
-
MyModel.objects.exclude(条件)
-
-
作用:
-
返回不包含此
条件
的 全部的数据集
-
-
示例:
-
查询
清华大学出版社,定价等于50
以外的全部图书books = Book.objects.exclude(pub="清华大学出版社", price=50) for book in books: print(book) Copy
-
7. 条件查询 - get
-
方法:
get(条件)
-
语法:
-
MyModel.objects.get(条件)
-
-
作用:
-
返回满足条件的唯一一条数据
-
-
说明:
-
该方法只能返回一条数据
-
查询结果多余一条数据则抛出,
Model.MultipleObjectsReturned
异常 -
查询结果如果没有数据则抛出
Model.DoesNotExist
异常
-
-
示例:
from bookstore.models import Book book = Book.objects.get(id=1) print(book.title) Copy
思考?如何做非等值的过滤查询,即 where id > 1
尝试: Book.objects.filter(id > 1) ?
查询谓词
定义:做更灵活的条件查询时需要使用查询谓词
说明:每一个查询谓词是一个独立的查询功能
-
__exact
: 等值匹配Author.objects.filter(id__exact=1) # 等同于select * from author where id = 1 Copy
-
__contains
: 包含指定值Author.objects.filter(name__contains='w') # 等同于 select * from author where name like '%w%' Copy
-
__startswith
: 以 XXX 开始 -
__endswith
: 以 XXX 结束 -
__gt
: 大于指定值Author.objects.filer(age__gt=50) # 等同于 select * from author where age > 50 Copy
-
__gte
: 大于等于 -
__lt
: 小于 -
__lte
: 小于等于 -
__in
: 查找数据是否在指定范围内-
示例
Author.objects.filter(country__in=['中国','日本','韩国']) # 等同于 select * from author where country in ('中国','日本','韩国') Copy
-
-
__range
: 查找数据是否在指定的区间范围内# 查找年龄在某一区间内的所有作者 Author.objects.filter(age__range=(35,50)) # 等同于 SELECT ... WHERE Author BETWEEN 35 and 50; Copy
详细内容参见: https://docs.djangoproject.com/en/2.2/ref/models/querysets/#field-lookups
更新操作
1. 更新单个数据
-
修改单个实体的某些字段值的步骤:
-
查
-
通过
get()
得到要修改的实体对象
-
-
改
-
通过
对象.属性
的方式修改数据
-
-
保存
-
通过
对象.save()
保存数据
-
-
如:
from bookstore.models import Book abook = Book.objects.get(id=10) abook.market_price = "10.5" abook.save() Copy
2. 批量更新数据
-
直接调用QuerySet的update(属性=值) 实现批量修改
-
返回值:更新数据的数量
-
如:
# 将id大于3的所有图书价格定为0元 books = Book.objects.filter(id__gt=3) books.update(price=0) # 将所有书的零售价定为100元 books = Book.objects.all() books.update(market_price=100) Copy
练习1: 制作 更新书籍 的页面
练习2: 制作 更新书籍的页面
点击 ‘查看所有书籍’页面中的 ‘更新’进入更新页面
视图函数 update_book
url
http://127.0.0.1:8000/bookstore/update_book/
更新页中显示当前书籍信息,且能对 定价和零售价进行修改
删除操作
-
删除记录是指删除数据库中的一条或多条记录
-
删除单个
MyModel
对象或删除一个查询结果集(QuerySet
)中的全部对象都是调用delete()
方法
1. 单个数据删除
-
步骤
-
查找查询结果对应的一个数据对象
-
调用这个数据对象的
delete()
方法实现删除
-
-
示例:
try: auth = Author.objects.get(id=1) auth.delete() except: print(删除失败) Copy
2. 批量删除
-
步骤
-
查找查询结果集中满足条件的全部
QuerySet
查询集合对象 -
调用查询集合对象的
delete()
方法实现删除
-
-
示例:
# 删除全部作者中,年龄大于65的全部信息 auths = Author.objects.filter(age__gt=65) auths.delete() Copy
3. 伪删除
-
通常不会轻易在业务里把数据真正删掉,取而代之的是做伪删除,即在表中添加一个布尔型字段(
is_active
),默认是True;执行删除时,将欲删除数据的is_active
字段置为False -
注意:用伪删除时,确保显示数据的地方,均加了
is_active=True
的过滤查询
练习:
点击 ‘查看所有书籍’页面中的 ‘删除’;删除当前书籍(伪删除)
视图函数 delete_book
路由 http://127.0.0.1:8000/bookstore/delete?book_id=xx
注意:相关查询获取数据的地方,要过滤出 活跃数据
F对象和Q对象
F 对象
一个F对象代表数据库中某条记录的字段的信息
作用:
-
通常是对数据库中的字段值在不获取的情况下进行操作
-
用于类属性(字段)之间的比较。
语法
from django.db.models import F F("列名") Copy
示例1 更新Book实例中所有的零售价涨10元
Book.objects.all().update(market_price=F('market_price')+10) 'UPDATE `bookstore_book` SET `market_price` = (`bookstore_book`.`market_price` + 10) # 以上做法好于如下代码 books = Book.objects.all() for book in books: book.market_price=book.marget_price+10 book.save() Copy
示例2 对数据库中两个字段的值进行比较,列出哪儿些书的零售价高于定价?
from django.db.models import F from bookstore.models import Book books = Book.objects.filter(market_price__gt=F('price')) 'SELECT * FROM `bookstore_book` WHERE `bookstore_book`.`market_price` > (`bookstore_book`.`price`) for book in books: print(book.title, '定价:', book.price, '现价:', book.market_price) Copy
Q 对象
当在获取查询结果集 使用复杂的逻辑或 |
、 逻辑非 ~
等操作时可以借助于 Q对象进行操作
如: 想找出定价低于20元 或 清华大学出版社的全部书,可以写成
Book.objects.filter(Q(price__lt=20)|Q(pub="清华大学出版社")) Copy
Q对象在 数据包 django.db.models
中。需要先导入再使用
-
作用
-
在条件中用来实现除
and(&)
以外的or(|)
或not(~)
操作
-
-
运算符:
-
&
与操作 -
|
或操作 -
〜
非操作
-
-
语法
from django.db.models import Q Q(条件1)|Q(条件2) # 条件1成立或条件2成立 Q(条件1)&Q(条件2) # 条件1和条件2同时成立 Q(条件1)&~Q(条件2) # 条件1成立且条件2不成立 ... Copy
-
示例
from django.db.models import Q # 查找清华大学出版社的书或价格低于50的书 Book.objects.filter(Q(market_price__lt=50) | Q(pub_house='清华大学出版社')) # 查找不是机械工业出版社的书且价格低于50的书 Book.objects.filter(Q(market_price__lt=50) & ~Q(pub_house='机械工业出版社')) Copy
聚合查询
-
聚合查询是指对一个数据表中的一个字段的数据进行部分或全部进行统计查询,查bookstore_book数据表中的全部书的平均价格,查询所有书的总个数等,都要使用聚合查询
聚合查询 — 整表聚合
-
不带分组的聚合查询是指导将全部数据进行集中统计查询
-
聚合函数【需要导入】:
-
导入方法:
from django.db.models import *
-
聚合函数:
Sum, Avg, Count, Max, Min
-
-
语法:
MyModel.objects.aggregate(结果变量名=聚合函数('列'))
-
返回结果:
-
由 结果变量名和值组成的字典
-
格式为:
{"结果变量名": 值}
-
-
示例:
# 得到所有书的平均价格 from bookstore.models import Book from django.db.models import Avg result = Book.objects.aggregate(myAvg=Avg('price')) print("平均价格是:", result['myAvg']) print("result=", result) # {"myAvg": 58.2} # 得到数据表里有多少本书 from django.db.models import Count result = Book.objects.aggregate(mycnt=Count('title')) print("数据记录总个数是:", result['mycnt']) print("result=", result) # {"mycnt": 10} Copy
聚合查询 — 分组聚合
-
分组聚合是指通过计算查询结果中每一个对象所关联的对象集合,从而得出总计值(也可以是平均值或总和),即为查询集的每一项生成聚合。
-
语法:
QuerySet.annotate(结果变量名=聚合函数('列'))
-
返回值:
QuerySet
-
用法步骤:
-
通过先用查询结果
MyModel.objects.values
查找查询要分组聚合的列-
MyModel.objects.values('列1', '列2')
-
如:
pub_set = Book.objects.values('pub') print(pub_set) # <QuerySet [{'pub': '清华大学出版社'}, {'pub': '清华大学出版社'}, {'pub_hou {'pub': '机械工业出版社'}, {'pub': '清华大学出版社'}]> Copy
-
-
通过返回结果的
QuerySet.annotate
方法分组聚合得到分组结果-
QuerySet.annotate(名=聚合函数('列'))
-
返回
QuerySet
结果集,内部存储结果的字典 -
如:
pub_count_set = pub_set.annotate(myCount=Count('pub')) print(pub_count_set) # <QuerySet [{'pub': '清华大学出版社', 'myCount': 7}, {'pub': '机械工业出版社', 'myCount': 3}]> Copy
-
-
原生数据库操作
Django
也可以支持 直接用 sql语句
的方式通信数据库
查询:使用MyModel.objects.raw()
进行 数据库查询操作查询
语法:MyModel.objects.raw(sql语句, 拼接参数)
返回值:RawQuerySet
集合对象 【只支持基础操作,比如循环】
books = models.Book.objects.raw('select * from bookstore_book') for book in books: print(book) Copy
SQL 注入
使用原生语句时小心 SQL注入
定义:用户通过数据上传,将恶意的sql语句提交给服务器,从而达到攻击效果
案例1: 用户在搜索好友的表单框里 输入 '1 or 1=1'
s1 = Book.objects.raw('select * from bookstore_book where id=%s') %('1 or 1=1') Copy
攻击结果:可查询出所有用户数据
sql注入防范
错误 -> s1 = Book.objects.raw('select * from bookstore_book where id=%s'%('1 or 1=1'))
正确 -> s2 = Book.objects.raw('select * from bookstore_book where id=%s',['1 or 1=1'])
原生数据库操作 — cursor
完全跨过模型类操作数据库 - 查询/更新/删除
-
导入
cursor
所在的包from django.db import connection Copy
-
用创建
cursor
类的构造函数创建cursor
对象,再使用cursor
对象,为保证在出现异常时能释放cursor
资源,通常使用with语句
进行创建操作from django.db import connection with connection.cursor() as cur: cur.execute('执行SQL语句', '拼接参数') Copy
示例:
# 用SQL语句将id 为 10的 书的出版社改为 "XXX出版社" from django.db import connection with connection.cursor() as cur: cur.execute('update bookstore_book set pub_house="XXX出版社" where id=10;') with connection.cursor() as cur: # 删除 id为1的一条记录 cur.execute('delete from bookstore_book where id=10;') Copy
关系映射
在关系型数据库中,通常不会把所有数据都放在同一张表中,不易于扩展,常见关系映射有:
-
一对一映射
如: 一个身份证对应一个人
-
一对多映射
如: 一个班级可以有多个学生
-
多对多映射
如: 一个学生可以报多个课程,一个课程可以有多个学生学习
一对一关联
定义
-
一对一是表示现实事物间存在的一对一的对应关系。
-
如:一个家庭只有一个户主,一个男人有一个妻子,一个人有一个唯一的指纹信息等
一对一创建语法
class A(model.Model): ... class B(model.Model): 属性 = models.OneToOneField(A, on_delete=xxx) Copy
外键类字段选项
特殊字段参数【必须项】:
-
on_delete
-
models.CASCADE
级联删除。 Django模拟SQL约束ON DELETE CASCADE
的行为,并删除包含ForeignKey
的对象。 -
models.PROTECT
抛出 ProtectedError 以阻止被引用对象的删除;[等同于mysql默认的RESTRICT] -
models.SET_NULL
设置ForeignKey null;需要指定null=True -
models.SET_DEFAULT
将ForeignKey设置为其默认值;必须设置ForeignKey的默认值。更多精彩内容,请参考文档 https://docs.djangoproject.com/en/2.2/ref/models/fields/#foreignkey
-
其余常用的字段选项【非必须项】;如:
-
null
-
unique 等
创建用法示例
1. 创建作家和作家妻子类
# file : oto/models.py from django.db import models class Author(models.Model): '''作家模型类''' name = models.CharField('作家', max_length=50) class Wife(models.Model): '''作家妻子模型类''' name = models.CharField("妻子", max_length=50) author = models.OneToOneField(Author, on_delete=models.CASCADE) # 增加一对一属性 Copy
2. 创建一对一的数据记录
from .models import * # 无外键的模型类[Author] author1 = Author.objects.create(name='王老师') # 有外键的模型内 [Author] wife1 = Wife.objects.create(name='王夫人', author=author1) # 关联王老师obj author2 = Author.objects.create(name='小泽老师') # 一对一可以没有数据对应的数据 Copy
数据查询
-
正向查询: 直接通过关联属性查询即可
# 通过 wife 找 author from .models import Wife wife = Wife.objects.get(name='王夫人') print(wife.name, '的老公是', wife.author.name) Copy
-
反向查询: 没有外键属性的一方,可以调用反向属性查询到关联的另一方
-
反向关联属性为
实例对象.引用类名(小写)
,如作家的反向引用为作家对象.wife
-
当反向引用不存在时,则会触发异常
# 通过 author.wife 关联属性 找 wife,如果没有对应的wife则触发异常 author1 = Author.objects.get(name='王老师') print(author1.name, '的妻子是', author1.wife.name) author2 = Author.objects.get(name='小泽老师') try: print(author2.name, '的妻子是', author2.wife.name) except: print(author2.name, '还没有妻子') Copy
-
一对多关联
定义
-
一对多是表示现实事物间存在的一对多的对应关系。
-
如:一个学校有多个班级,一个班级有多个学生, 一本图书只能属于一个出版社,一个出版社允许出版多本图书
一对多需要明确具体角色,在多表上设置外键
一对多创建语法
-
当一个A类对象可以关联多个B类对象时
class A(model.Model): ... class B(model.Model): 属性 = models.ForeignKey("一"的模型类, on_delete=xx) Copy
ForeignKey 必需指定 on_delete模式
创建用法示例
有二个出版社对应五本书的情况.
-
清华大学出版社
有书
-
C++
-
Java
-
Python
-
-
北京大学出版社
有书
-
西游记
-
水浒
-
1. 模型类创建
# file: otm/models.py from django.db import models class Publisher(models.Model): '''出版社【一】''' name = models.CharField('名称', max_length=50, unique=True) class Book(models.Model): '''书【多】''' title = models.CharField('书名', max_length=50) publisher = ForeignKey(Publisher, on_delete=models.CASCADE) Copy
2. 创建数据
# 先创建 '一' ,再创建 '多' from .models import * pub1 = Publisher.objects.create(name='清华大学出版社') Book.objects.create(title='C++', publisher=pub1) Book.objects.create(title='Java', publisher_id=1) Copy
数据查询
-
正向查询 【通过 Book 查询 Publisher】
通过 publisher 属性查询即可 book.publisher abook = Book.objects.get(id=1) print(abook.title, '的出版社是:', abook.publisher.name) Copy
-
反向查询 【通过 Publisher 查询 对应的所有的 Book】
需要得到反向属性
Django会在Publisher中增加一个属性来表示对对应的Book们的查询引用 属性:book_set 等价于 objects # 通过出版社查询对应的书 pub1 = Publisher.objects.get(name='清华大学出版社') books = pub1.book_set.all() # 通过book_set 获取pub1对应的多个Book数据对象 # books = Book.objects.filter(publisher=pub1) # 也可以采用此方式获取 print("清华大学出版社的书有:") for book in books: print(book.title) Copy
多对多关联
定义
-
多对多表达对象之间多对多复杂关系,如: 每个人都有不同的学校(小学,初中,高中,...),每个学校都有不同的学生...
-
mysql
中创建多对多需要依赖第三张表来实现 -
Django
中无需手动创建第三张表,Django
自动完成
多对多语法
-
在关联的两个类中的任意一个类中,增加:
属性 = models.ManyToManyField(MyModel) Copy
创建用法示例
-
一个作者可以出版多本图书
-
一本图书可以被多名作者同时编写
class Author(models.Model): ... class Book(models.Model): ... authors = models.ManyToManyField(Author) Copy
1. 创建模型类
class Author(models.Model): '''作家模型类''' name = models.CharField('作家', max_length=50) def __str__(self): return self.name class Book(models.Model): '''书模型类''' title = models.CharField('书名', max_length=50) authors = models.ManyToManyField(Author) def __str__(self): return self.title Copy
2. 创建数据
-
方案1 先创建 author 再关联 book
author1 = Author.objects.create(name='吕老师') author2 = Author.objects.create(name='王老师') # 吕老师和王老师同时写了一本Python book11 = author1.book_set.create(title="Python") author2.book_set.add(book11) Copy
-
方案2 先创建 book 再关联 author
book = Book.objects.create(title='python1') # 郭小闹和吕老师都参与了 python1 的 创作 author3 = book.authors.create(name='guoxiaonao') book.authors.add(author1) Copy
数据查询
-
正向查询 有多对多属性的对象 查 另一方
通过
Book
查询对应的所有的Author
此时多对多属性 等价于
objects
book.authors.all() -> 获取 book 对应的所有的author的信息 book.authors.filter(age__gt=80) -> 获取book对应的作者中年龄大于80岁的作者的信息 Copy
-
反向查询
通过
Author
查询对应的所有的Book
利用反向属性
book_set
-
Django
会生成一个反向属性book_set
用于表示对对应的book
的查询对象相关操作author.book_set.all() author.book_set.filter() Copy
行政后台数据库管理
什么是 Admin 管理后台
-
django
提供了比较完善的后台管理数据库的接口,开发过程中调用和测试使用 -
django
会所有所有已注册的模型类,为这些模型类提开数据管理界面,供开发者使用
管理员配置步骤
创建后台管理权限 - 该账号为管理后台最高权限账号
python3 manage.py createsuperuser 复制
-
可知提示完成注册,参考如下:
$ python3 manage.py createsuperuser Username (leave blank to use 'tarena'): tarena # 此处输入用户名 Email address: laowei@tedu.cn # 此处输入邮箱 Password: # 此处输入密码(密码要复杂些,否则会提示密码太简单) Password (again): # 再次输入重复密码 Superuser created successfully. $ 复制
-
后台管理的登录地址:
用刚注册的管理员账号登陆
注册自定义模型类
想定义自己的模型类也能在/admin
后台管理界中显示和管理,需要将自己的类注册到后台管理界面
注册步骤:
-
在应用
app
中的admin.py
中导入要管理的模型models
类,如:from .models import Book 复制
-
调用
admin.site.register
方法进行注册,如:from django.contrib import admin admin.site.register(自定义模型类) 复制
-
在 bookstore/admin.py 添加如下代码对Book类进行管理
示例:
# file: bookstore/admin.py from django.contrib import admin # Register your models here. from . import models ... admin.site.register(models.Book) # 将Book类注册为可管理页面 复制
修改自定义模型类的造型样式
-
在
admin
后台管理数据库中对自定义的数据记录都展示为XXXX object
类型的记录,不便于阅读和判断 -
在用户自定义的模型类中可以改写
def __str__(self):
方法解决问题,例如:-
在自定义模型类中改写
__str__(self)
方法返回显示文字内容:class Book(models.Model): ... def __str__(self): return "书名" + self.title 复制
-
模型管理器类
作用:
-
为后台管理界面添加便利操作的新功能。
说明:
-
后台管理器类须继承自
django.contrib.admin
里的ModelAdmin
类
模型管理器的使用方法:
-
在
<应用app>/admin.py
里定义模型管理器类class XXXXManager(admin.ModelAdmin): ...... 复制
-
绑定注册模型管理器和模型类
from django.contrib import admin from .models import * admin.site.register(YYYY, XXXXManager) # 绑定 YYYY 模型类与 管理器类 XXXXManager 复制
-
示例:
# file : bookstore/admin.py from django.contrib import admin from .models import Book class BookManager(admin.ModelAdmin): list_display = ['id', 'title', 'price', 'market_price'] admin.site.register(Book, BookManager) 复制
进入http://127.0.0.1:8000/admin/bookstore/book/查看显示方式和以前不同
-
模型管理器类
ModelAdmin
中实现的高级管理功能
-
list_display
去控制哪些字段会显示在Admin
的修改列表页面中。 -
list_display_links
可以控制list_display
中的字段是否应该链接到对象的“更改”页面。 -
list_filter
设置Admin
过滤激活修改列表页面列表的器 -
search_fields
设置Admin
启用更改列表页面上的搜索框。 -
list_editable
设置为模型上的字段名称列表,这将允许在更改列表页面上进行编辑。 -
其他参见https://docs.djangoproject.com/en/2.2/ref/contrib/admin/
-
-
再谈元类
通过Meta
内嵌定义类模型类的属性
-
模型类可以通过定义内部类
class Meta
来重新定义当前模型类和数据表的一些属性信息 -
使用格式如下:
class Book(models.Model): title = CharField(....) class Meta: 1. db_table = '数据表名' - 该模型所用的数据表的名称。(设置完成后需要立马更新同步数据库) 2. verbose_name = '单数名' - 给模型对象的一个易于理解的名称(单数),用于显示在/admin管理界面中 3. verbose_name_plural = '复数名' - 该对象复数形式的名称(复数),用于显示在/admin管理界面中 复制
练习:
-
将
Author
模型加入后台管理 -
制作一个
AuthorManager
管理器类,让后台管理Authors
列表中显示作者的ID、姓名、年龄信息
-
用后台管理程序添加三条
Author
记录 -
修改其中一条记录的年龄 -
Author
-
删除最后一条添加的记录 -
Author
会话保持
-
会话 - 从打开浏览器访问一个网站,到关闭浏览器结束此次访问,称之为一次会话
-
HTTP协议是无状态的,导致会话状态难以保持
-
试想一下,如果不保持会话状态,在电商网站购物的场景体验?
Cookies和Session就是为了保持会话状态而诞生的两个存储技术
Cookies 定义
-
cookies
是保存在客户端浏览器上的存储空间 -
Chrome 浏览器 可能通过开发者工具的
Application
>>Storage
>>Cookies
查看和操作浏览器端所有的Cookies
值 -
火狐浏览器 可能通过开发者工具的
存储 -> Cookie
Cookies 特点
-
cookies
在浏览器上是以键-值对
的形式进行存储的,键和值都是以ASCII字符串的形存储(不能是中文字符串) -
存储的数据带有
生命周期
-
cookies中的数据是
按域存储隔离
的,不同的域之间无法访问 -
cookies 的内部的数据会在每次访问此网址时都会携带到服务器端,如果cookies过大会降低响应速度
Cookies 的使用
在Django 设置浏览器的COOKIE
必须通过 HttpResponse对象
来完成
1. 存储 和 修改
HttpResponse.set_cookie(key, value='', max_age=None, expires=None) Copy
-
key:cookie
的名字 -
value:cookie
的值 -
max_age:cookie
存活时间,秒为单位 -
expires
:具体过期时间 -
当不指定max_age和expires 时,关闭浏览器时此数据失效
示例
以下示例均在视图函数中调用
2. 添加cookie
# 为浏览器添加键为 my_var1,值为123,过期时间为1个小时的cookie responds = HttpResponse("已添加 my_var1,值为123") responds.set_cookie('my_var1', 123, 3600) return responds Copy
3. 修改cookie
# 为浏览器添加键为 my_var1,修改值为456,过期时间为2个小时的cookie responds = HttpResponse("已修改 my_var1,值为456") responds.set_cookie('my_var1', 456, 3600*2) return responds Copy
4. 删除COOKIE
-
HttpResponse.delete_cookie(key)
-
删除指定的key 的Cookie。 如果key 不存在则什么也不发生。
示例
# 删除浏览器键为 my_var1的cookie responds = HttpResponse("已删除 my_var1") responds.delete_cookie('my_var1') return responds Copy
5. 获取cookie
-
通过
request.COOKIES
绑定的字典(dict) 获取客户端的 COOKIES数据value = request.COOKIES.get('cookies名', '默认值') print("cookies名 = ", value) Copy
示例
# 获取浏览器中 my_var变量对应的值 value = request.COOKIES.get('my_var1', '没有值!') print("cookie my_var1 = ", value) return HttpResponse("my_var1:" + value) Copy
session
Session定义
-
session又名会话控制,是在服务器上开辟一段空间用于保留浏览器和服务器交互时的重要数据
-
实现方式
-
使用 session 需要在浏览器客户端启动 cookie,且用在cookie中存储sessionid
-
每个客户端都可以在服务器端有一个独立的Session
-
注意:不同的请求者之间不会共享这个数据,与请求者一一对应
-
session 初始配置
-
在
settings.py
文件中 -
向
INSTALLED_APPS
列表中添加:
INSTALLED_APPS = [ # 启用 sessions 应用 'django.contrib.sessions', ] Copy
-
向
MIDDLEWARE
列表中添加:
MIDDLEWARE = [ # 启用 Session 中间件 'django.contrib.sessions.middleware.SessionMiddleware', ] Copy
session的基本操作
-
session对于象是一个类似于字典的SessionStore类型的对象, 可以用类拟于字典的方式进行操作
-
session 只能够存储能够序列化的数据,如字典,列表等。
-
保存 session 的值到服务器
-
request.session['KEY'] = VALUE
-
-
获取session的值
-
VALUE = request.session['KEY']
-
VALUE = request.session.get('KEY', 缺省值)
-
-
删除session的值
-
del request.session['KEY']`
-
在 settings.py 中有关 session 的设置
-
SESSION_COOKIE_AGE
-
作用: 指定sessionid在cookies中的保存时长(默认是2周),如下:
-
SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2
-
-
SESSION_EXPIRE_AT_BROWSER_CLOSE = True 设置只要浏览器关闭时,session就失效(默认为False)
注: 当使用
session
时需要迁移数据库,否则会出现错误
django 原生session 问题:
-
django_session表是 单表设计; 且该表数据量持续增持【浏览器故意删掉sessionid&过期数据未删除】
-
可以每晚执行 python3 manage.py clearsessions 【该命令可删除已过期的session数据】
Cookies 和 session对比
种类 | 存储位置: | 安全性 |
---|---|---|
Cookies |
浏览器中 | 相对不安全 |
session |
服务器中(mysql) | 相对安全 |
不管
Cookies
还是Session
, 不要存储敏感数据 【密码】
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
· Manus的开源复刻OpenManus初探