Django的学习之路-基础
1. Django 项目创建
1.项目结构
! swz 100173 swz 100174 swz 100172
1.1.设置.py 文件
"""
mydemo 项目的 Django 设置。
由 'django-admin startproject' 使用 Django 3.1.7 生成。<django 版本
有关此文件的更多信息,请参阅
https://docs.djangoproject.com/en/3.1/topics/settings/
有关设置及其值的完整列表,请参阅
https://docs.djangoproject.com/en/3.1/ref/settings/
"""
从 pathlib 导入路径
在项目中构建路径,如下所示:BASE_DIR / 'subdir'。
BASE_DIR u003d Path(__file__).resolve().parent.parent """<显示当前项目根目录"""
快速启动开发设置 - 不适合生产
见 https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/
SECURITY WARNING:将生产中使用的密钥保密!
秘密_KEY u003d 'jb^(bip2g_@%r*5ni-8@#yz%*crzw7sqpq_qcbhw48lgk+ctxo'
安全警告:不要在生产环境中打开调试运行!
调试 u003d 真
"""
调试模式开关,默认为True(Debug Mode)
by True When:1.检测到代码变化后立即重启服务; 2.显示错误页面
by False When(官方启动模式)/在线模式:一定要把项目改成上线时 False
"""
允许_HOSTS u003d []
"""
允许的域名,只有列表中添加的域名才能访问服务器,默认允许127.0.0.1或者localhost访问
设置为“*”:表示允许所有域名访问
设置当前局域网中的域名进行访问:
1.项目启动时的设置:python manage.py runserver 0.0.0.0:8000
2.添加局域网IP
"""
应用程序定义
已安装_APPS u003d [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
中间件 u003d [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF u003d 'demo.urls'
"""
项目主路由位置,默认在项目文件夹urls.py下
"""
模板 u003d [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS':是的,
“选项”:{
'上下文_处理器':\ [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
"""
模板配置
"""
WSGI_APPLICATION u003d 'mydemo.wsgi.application'
数据库
https://docs.djangoproject.com/en/3.1/ref/settings/#databases
数据库 u003d {
“默认”:{
“引擎”:“django.db.backends.sqlite3”,
'名称': BASE_DIR / 'db.sqlite3',
}
}
密码验证
https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS u003d [
{
“名称”:“django.contrib.auth.password_validation.UserAttributeSimilarityValidator”,
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
国际化
https://docs.djangoproject.com/en/3.1/topics/i18n/
语言_CODE u003d 'en-us'
"""
首页语言配置,可设置为中文
语言_CODE u003d 'zh-hans'
"""
TIME_ZONE u003d 'UTC'
"""
时区设置,主要影响数据库时间显示
TIME\ZONE u003d '亚洲/上海'
"""
使用_I18N u003d 真
使用_L10N u003d 真
使用_TZ u003d 真
静态文件(CSS、JavaScript、图像)
https://docs.djangoproject.com/en/3.1/howto/static-files/
静态_URL u003d '/静态/'
"""
静态文件路由
"""
1.2 网址
-
URL结构:protocol://hostname[:port]/path[?query][#fragment]
-
协议:
-
Http:通过HTTP访问资源,格式为:http://
-
https:通过安全的https:访问资源格式:https://
-
文件:通过文件访问本地资源,格式:file:///
-
主机名(主机名/域名):
-
存储资源的服务器的域名系统 (DNS) 主机名、域名或 IP 地址
-
港口:
-
可选,省略时使用架构的默认端口
-
每个传输协议都有一个默认端口号http:默认80,默认443
-
路径(路由地址):
-
由零个或多个'/'符号分隔的字符串,通常用于表示主机上的目录或文件地址,路由地址决定服务器如何处理请求
-
查询(查询字符串):
-
可选,带'?'开头,用于传递参数给动态网页,可以传递多个参数,用'&'隔开,参数名和值用等号隔开keyu003dvalue
-
片段:
-
以'#'开头的字符串,指定网络资源中的一个片段,类似于书签,下次访问时可以定位到该片段
-
Django 如何处理 URL 请求
1.根据浏览器传过来的URL,django按照ROOT_从配置文件URLCONF中找到主路由文件;默认情况下,路由文件位于相同目录名下的 URL 中。在 PY
2.django加载主路由中的urlpattern变量,是很多路由的列表
3.从上到下匹配urlpattern中的路径,然后通过匹配到第一个满足的路径来中断后续匹配
4.匹配成功,调用对应的视图函数处理请求并返回对应的响应
5.匹配失败,返回404响应
1.3 查看功能
-
定义:用于接收浏览器请求(HttpRequest对象)并通过HttpResponse对象返回响应的函数
-
语法:return 必须是一个 HttpResponse 对象
def demoview(请求[,其他参数]):
return HttpResponse('要返回的数据')
- 示例:
在与项目同名的目录中创建视图。 PY
从 django.http 导入 HttpResponse
def page1\view(请求):
html u003d "<h1>你好世界</h1>"
返回 HttpResponse(html)
添加路由url.py
从 django.contrib 导入管理员
从 django.urls 导入路径
从 .导入视图
url 模式 u003d [
路径('admin/', admin.site.urls),
路径('page1/',views.page1_view),
]
1.4 路由配置-path
-
path() 函数
-
从 django.urls 导入路径导入
-
语法 path(route,views,nameu003dNone)
-
参数:
-
route:字符串类型,匹配请求路径
-
views:指定路径对应的视图处理函数的名称
-
name:地址的别名,用于模板中的反向地址解析
-
路径转换器
-
语法:<转换器类型:自定义名称>
-
作用:如果转换器类型匹配对应的数据类型,则将数据作为关键字参数传递给视图函数
-
示例:path('page/int:page',views.xxx),如果在page path后面匹配到int类型,则将接收到的path中的数据赋值给变量page,然后传递给view作为关键参数
-
转换器类型
影响
样本
字符串
匹配除'/'以外的非空字符串
"v1/users/str:username"match/v1/users/china,匹配结果为:usernameu003dchina
整数
将 0 匹配到任何正整数,返回一个 int
"v1/users/int:num"match/v1/users/35,匹配结果为:numu003d35
蛞蝓
匹配任何带有 ASCII 字母或数字以及连字符和下划线的短标签
"v1/users/slug:sl"匹配/v1/users/this_is_django,匹配结果为:slu003dthis_is_django
小路
匹配非空字段,包括路径分隔符“/”
"v1/users/path:ph"匹配/v1/users/goods/a/b/c,匹配结果为:phu003dgoods/a/b/c
-
re_path 转换器
-
语法:re_path(reg,view,nameu003dxxx)
-
正则表达式必须命名为分组模式(?P<name>pattern;成功匹配后作为关键字参数传递给视图函数
-
作用:使用正则进行精确匹配
-
示例:URL (r'^weather/(?P<city>[a-z]+)/(?P<year>\d{4})/$', views. Weather),
2.请求和响应
2.1.请求和响应
2.1. 1 Django 中的请求
-
视图函数中的第一个参数是HttpRequest对象
-
当django收到一个http协议的请求时,会根据请求数据报创建一个HttpRequest对象
-
HttpRequest对象通过属性描述了请求的所有相关信息
-
HttpRequest 属性:
性别名称
解释
th_info
网址字符串
方法
表示 Http 请求方法的字符串:GET、POST、PUT 等。
外星人
QueryDict 查询字典对象,包含有关如何请求获取的所有数据
邮政
QueryDict 查询字典的对象,包含所有关于如何请求 post 的数据
ILES
包含所有上传文件信息的类字典对象
OOKIES
将所有 cookie 、键和值作为字符串的 python 字典
会话
类似于字典对象,代表当前会话
奥迪
字符串请求正文的内容
称呼
请求协议(http 或 https)
equest.get_full_path()
请求的全路径会一起取出查询字符串
equest.META
请求中的元数据(标头)
请求.META['REMOTE_ADDR']
客户端 IP 地址
2.1. 2 Django 中的响应对象
-
构造函数:
-
HttpResponse (contentu003dresponder, content_typeu003dresponder 数据类型, statusu003d状态码)
-
效果:
-
以响应量将响应返回给客户端浏览器
-
参数:
-
内容:代表返回的内容
-
status_code:返回HTTP响应状态码(默认为200)
-
content_type:指定浏览器显示数据的 MIME 类型(默认为 text/html)
-
共同内容_type:
-
'text/html': 默认,HTML 文件
-
'text/plain': 纯文本
-
'text/css': CSS 文件
*'文本/javascript':js文件
-
'multipart/form-data': 文件提交
-
'application/json': JSON 传输
-
'应用程序/xml': XML 文件
-
HttpResponse 子类
类型
影响
状态码
HttpResponse重定向
重定向
302
未修改 Http 响应
没有改变
304
HttpResponseBadRequest
错误请求
400
HttpResponseNotFound
没有对应的资源
404
HttpResponseForbidden
请求被禁止
403
Http 响应服务器错误
服务器错误
500
2.2 GET 和 POST 请求
-
定义:
-
无论是GET还是POST,统一由view函数接收,决定request.method区分具体的请求动作
-
样本
如果 request.method u003du003d 'GET':
根据请求处理获取业务逻辑
elif request.method u003du003d 'POST':
根据请求处理 POST 业务逻辑
其他:
处理其他请求的逻辑
-
GET处理
-
GET 请求动作通常用于从服务器获取数据
-
能够生成 GET 请求的场景
-
输入网址后浏览器地址栏
-
<a href u003d "地址?参数u003d值&参数u003d值">
-
表单中的方法是get
-
在GET请求中,如果有数据要传给服务器,一般是通过Query String来传递的,注意不要传递敏感数据
-
网址格式:XXX?参数名称 1 u003d 值 & 参数名称 2 u003d 值(例如:http://127.0.0.1:8000?au003d100&bu003d200 )
-
服务器端接收参数:如何获取客户端请求 GET 提交的数据的示例
request.GET['Parameter Name'] #获取参数名的值
request.GET.get('Parameter Name','Default value') #获取参数名的值,如果参数名不存在则返回默认值
request.GET.getlist('Parameter Name') #如果此参数名称存在多个返回值,则使用getlist接收```
-
POST 处理
-
POST 请求动作通常用于向服务器提交大型/私有数据
-
客户端通过表单等POST请求向服务器传递数据;例如:
<form methodu003d'post' actionu003d"/login"> #action 指定post请求发送到哪个路由
全名:<input typeu003d"text" nameu003d"username">
<输入类型u003d'提交'值u003d'土地'>
</form>
-
服务器端接收参数:通过request.method判断是否为post请求
-
使用 post 接收客户数据
request.POST['Parameter Name'] #获取参数名的值
request.POST.get('Parameter Name','Default value') #获取参数名的值,如果参数名不存在则返回默认值
request.POST.getlist('Parameter Name') #如果该参数名存在多个返回值,则用getlist接收
-
注意:django 发送 POST 请求时需要取消 csrf 验证,否则 django 会拒绝客户端的 POST 请求并报 403 响应
-
取消 csrf 验证:注释掉设置。 py 文件中 MIDDLEWARE 中 csrfviewmiddleware 的 MIDDLEWARE
2.3 Django 设计模式(MTV)
-
设计模式:MVC和MTV
-
MVC(模型-视图-控制器)模型-视图-控制器模式
-
M Model Layer,主要用于数据库层的封装
-
V View Layer 用于向用户展示结果
-
处理请求、获取数据、返回结果的C控制层
-
优点:减少模块之间的耦合
-
MTV(模型-模板-视图)模型-模板-视图模式
-
M Model Layer,负责与数据库交互
-
T Template Layer,负责将内容渲染到浏览器(html)
-
V视图层,负责接收请求,获取数据,返回结果
-
优点:减少模块之间的耦合
2.4 模板层
-
模板定义:
-
模板是可以根据字典数据动态变化的 HTML 页面
-
模板可以根据视图传入的字典数据动态生成HTML页面
-
模板配置
-
创建模板文件夹<项目名称>/templates
-
在设置。 PY中的TEMPLATES配置项
-
BACKEND:具有指定模板的引擎
-
DIRS:模板的搜索目录,可以是一个或多个
-
APP_DIRS:是否要在子应用的templates文件夹中搜索模板文件
-
OPTIONS:模板选项
-
部分配置需要修改
-
设置 DIRS -'DIRS': [os.path.join(BASE_DIR,'templates')]
-
模板是如何加载的
-
场景一:通过loader获取模板,通过HttpResponse响应,在视图函数中配置如下
从 django.template 导入加载器
t u003d loader.get_template("模板文件名") #用loader加载模板给出一个loader对象
html u003d t.render(Dictionary data) #将t(加载器对象)转换为HTML字符串
return HttpResponse(html) #将转换后的String内容返回给浏览器响应对象
- 场景二:使用render()直接加载和响应模板,在函数视图中配置如下
从 django.shortcuts 导入渲染
return render(request,'模板文件名',字典数据)
-
视图层和模板层的交互
-
视图函数将python变量封装成字典,传递给模板。例子:
def xxx_view(请求):
迪克 u003d {
"变量 1":"值 1",
"变量 2":"值 2",
}
返回渲染(请求,'xxx.html',div)
-
在模板中,我们可以使用 {{variable name}} 的语法来调用视图传入的变量
-
模板层-变量
-
模板层可以接收的数据类型
类型名称
笔记
字符串
字符串
整数
整数
列表
列表
元组
元组
听写
字典
功能
方法
对象
类实例化对象
-
在模板中使用变量语法
-
{{变量的名称}}
-
{{Variable Name.index}} #传入的变量是列表、元组等,可用。 index方法取出元素
-
{{Variable Name.key}} #传入的变量是字典,可用。 key方法获取key的值
-
{{Object.Method}} #调用对象的方法
-
{{函数名称}} #调用函数
-
模板标签
-
它的作用:将一些服务器端功能嵌入到模板中,例如流程控制
-
语法:
{% 标签 %}
............
{% End label %} #django中大部分标签都需要用结束标签密封
-
如果标签
-
语法
{% if 条件表达式 1 %}
......
{% elif 条件表达式 2 %}
......
{% 其他 %}
......
{% endif %} #必须以endif标签结尾
-
当心:
-
如果条件表达式可以使用运算符u003du003d,!u003d,<,>,<u003d,>u003d, In 的示例。不在,是,不是,不是,和,或;
-
在 if 标记中使用实际括号是无效的语法,如果需要它们来指示优先级,则应使用嵌套的 if 标记
-
在 if 语句中,变量或常量不能在运算符的任一侧相邻;它们必须用空格分隔
-
if 标签的语法参考官方文档
-
样本
<form actionu003d'/text' methodu003d"post">
<input typeu003d"text" nameu003d"x" valueu003d'{{ x }}'>
<选择名称u003d“操作”>
<option valueu003d"add" {%if op u003du003d 'add' %}selected{%endif%}> +plus</option>
<option valueu003d"sub" {%if op u003du003d 'sub' %}selected{%endif%}> -reduce</option>
<option valueu003d"mul" {%if op u003du003d 'mul' %}selected{%endif%}> *ride</option>
<option valueu003d"div" {%if op u003du003d 'div' %}selected{%endif%}> /except</option>
</选择>
<input typeu003d"text" nameu003d"y" valueu003d'{{ y }}'> u003d <span>{{ result }}</span>
<div><input typeu003d"submit" valueu003d"开始计算">
</div>
</form>
-
用于标签
-
语法:
{% for variable in Iterable Objects %}
...... 循环语句
{% 空 %}
...... Iterable 对象为空时显示的语句
{% endfor %}
-
将可迭代对象从视图函数传递到模板文件作为字典要求模板文件中的可迭代对象名称与视图函数中定义的键名相同 <h3>{% for I in X%}{{forloop. counter}} this is in for {{i} {%endfor%}</h3> # x 由 View Functions 传入
-
for 标签的语法参考官方文档
-
内置变量 - for 循环
多变的
描述
forloop.counter
返回当前循环的索引(从 1 开始的索引)
forloop.counter0
返回当前循环的索引(从 0 开始的索引)
for loop.rev 计数器
返回当前循环的索引(从索引计数器值的开始反转)
forloop.revcounter0
返回当前循环的索引(从 0 反转计数器值)
forloop.first
如果当前循环是第一个循环,则返回 True
forloop.last
如果当前循环是最后一个循环,则返回 True
forloop.parentloop
如果是嵌套循环,则parentloop代表外循环
-
模板过滤器
-
定义:输出时处理一个变量的值
-
作用:可以使用过滤器改变变量的输出显示
-
语法:{{变量|Filter1:'参数值1'|Filter2:'参数值2'}}
-
过滤器语法参考官方文档
-
常用过滤器:
筛选
解释
降低
将字符串全部转换为小写
上
将字符串全部转换为大写
安全的
禁用转义并告诉模板这个变量是安全的并且可以解释执行
添加:“n”
将 value 的值增加 n
默认值:'默认值'
如果变量不存在则返回默认值
截断字符:'n'
如果字符串的字符数超过指定数量,则会被截断,截断后的字符串将以省略号('...')的可翻译序列结尾
-
模板的继承
-
定义:模板的继承重用父模板的内容,而子模板直接继承父模板的所有内容并覆盖父模板中的相应块
-
在语法父模板中:
-
在父模板中定义块标签
-
识别允许修改哪些子模块(可以修改块标签继承)
-
块标签:在父模板中定义并在子模板中覆盖
-
在语法子模板中:
-
继承模板extends标签(写在模板文件的第一行)
-
例如,{% extends'base.html'%}#继承父模板库。 HTML
-
子模板覆盖父模板中的内容块
{% 块块_name %}
子模板块用于覆盖父模板块_name块的内容
{% endblock block_name %} #block_name 可以省略
-
覆盖规则被覆盖:
-
不覆盖,会显示为父模板效果
-
重写,然后显示为重写效果
-
注意:模板继承时,服务器端的动态内容不能被继承,例如视图传给父模板的变量在子模板中是无法获取的
-
示例:在父模板中
{% 块块_name %}
<h4>这是在父母中</h4>
{% 端块 %}
在子模板中
{% 扩展 'test_html.html' %}
{% 块块_name %}
<h3> 这是在base.html </h3>
{% 端块 %}
- 过滤器语法参考官方文档
2.5 URL反向解析
-
网址:
-
代码中经常出现 URL 的位置:
-
模板[在 HTML]:
-
<a hrefu003d'url'>超链接</a> #点击后页面跳转到URL
-
<form actionu003d'URL'methodu003d'post'> #form 表单中的数据 使用 post 方法提交值 URL
-
查看函数 - 302 Jump HttpResponseRedirect('url') #将用户地址栏中的地址跳转到URL
-
用代码编写 URL 规范:
-
绝对地址:http://127.0.0.1:8000/page1(写出所有协议、域名、端口、路径)
-
相对地址:
1、'/page/1':'/'开头的相对地址,浏览器在当前地址栏中添加协议、IP、端口作为最终访问地址。例如: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定义的名称在视图或模板中动态查找或计算对应的路由
-
语法:
-
路径(路线,视图,名称u003d'别名')
-
示例:path('page', views.page_view,name u003d'page_url')
-
根据路径中传递给它的 name 关键字为 URL 赋予一个唯一的名称,可用于在模板或视图中向后推断此 URL 信息
-
模板 - 通过 URL 标签反向地址解析
-
{% url'别名'%}
-
{%url'Alias''参数值1''参数值2'%},参数值1:传入路由的参数
-
例子
{%url'page1''100'%} #解析nameu003dpage1的路由,传入参数100
{% URL'page2'key1u003d'1' key2u003d'2'%} #解析nameu003dpage2的路由,关键字通过key1,key2注意路由解析时传入的参数都是字符串传入
- 在视图函数中 - 通过在 django 中调用 Reverse 方法来反向解析
从 django.urls 导入反向
reverse('别名', argsu003d[ ], kwargsu003d{ })
#示例:
reverse('page1',argsu003d[100]) #解析nameu003dpage1的路由,传入参数100
反向('page2',kwargsu003d{key1u003d1,key2u003d2})
3.静态文件
-
定义:项目中的css、图片、js、音频、视频等
-
静态文件配置
-
静态文件使用配置(settings.py):
-
配置静态文件的访问路径,创建项目时默认存在
-
静态文件可以在那个 URL 地址找到
-
静态_URL u003d '/静态/'
-
说明:指定静态文件需要通过/static/xxx还是http://127.0.0.1:8000/static/xxx访问,其中xxx代表具体的静态资源位置
-
配置静态文件的存储路径 STATICFILES_DIRS, STATICFILES_DIRS 保存静态文件在服务器上的存储位置
#file:settings.py
静态文件_DIRS u003d (
os.path.join(BASE_DIR,'static'),
)
-
静态文件访问
-
通过模板访问静态文件,例如:
<img srcu003d"http://127.0.0.1:8000/static/image1.jpg "widthu003d" 200 "heightu003d" 200 "> #绝对路径访问
<img srcu003d"static/image2.jpg" widthu003d"200" heightu003d"200" > #相对路径访问
- 静态文件加载推荐通过 {% static%} 标签访问静态文件
- 加载静态 - {% load static%}
2.使用静态资源-{%static'静态资源路径'%}
3.示例:<img srcu003d'{%static'images/lena.jpg'%}' > 访问静态文件夹下的images文件夹中的Lena。 JPG
4.应用程序和路由
-
应用:
-
定义:是django项目中独立的业务模块,可以包含自己的路由、视图、模板、模型
-
创建一个应用程序:
-
使用管理。 py中的子命令startapp创建应用程序文件夹
python manage.py startapp app_name #子应用名称不能与python关键字重复
! swz 100188 swz 100189 swz 100187
-
在设置。 INSTALLED_in py 文件 配置在APPS列表中安装这个应用
-
例子:
已安装_APPS u003d [
#......
'app1_name', #应用程序名称
'app2_name',
]
- 分布式路由
django 中的主路由配置文件(urls.py)不处理用户特定的路由,主路由配置文件做请求分发(分布式请求处理)。具体的请求可以由它们各自的应用程序处理。
- 分布式路由配置:
1.在主路由中调用include函数
-
语法:include('app_name.url 模块名')
-
作用:用于将当前路由转移到应用程序的路由配置文件中进行分布式处理的urlpatterns
-
以 http://127.0.0.1:8000/users/index 为例
从 django.urls 导入 psth,包括
从 .导入视图
url 模式 u003d [
路径('admin/',admin.site.urls),
path('users/',include('users.urls')) #分发给子应用用户的URL。 PY
]
- 在应用程序下配置 URL。 PY
- 在应用程序文件夹下手动创建 URL。 py,内容结构和主路由一模一样
从 django.urls 导入路径
从 .导入视图
url 模式 u003d [
#http://127.0.0.1:8000/users/index
路径('索引',views.index_view)
]
-
正在申请的模板
-
模板目录也可以通过以下方式在内部配置:
-
在应用程序下手动创建模板文件夹
-
在设置。在 PY 中打开应用程序模板功能
-
INSTALLED_ 'APP_in APPS配置项DIRS'值为True
-
注意:django 的 Find Templates 规则适用于同时存在模板和外部模板时:
-
先在外层模板目录中查找模板
-
如果在外层templates目录下没有找到匹配的模板,按INSTALLED_APPS配置下的应用顺序从上到下一层一层找到
-
避免子应用中的模板文件名重复-> 解决方法:在子应用下的templates目录下创建一个与子应用同名的文件夹,将模板文件放在同名文件夹下,将模板插入视图函数的路径更改为子应用程序名称。模板文件名
例子:
从 django.shortcuts 导入渲染
在此处创建您的视图。
def 索引_view(请求):
返回渲染(请求,'news/index.html')
5. ORM模型
5.1 数据库
-
模型层 - 负责与数据库通信
-
django 配置 MySQL
1.使用mysqlclient[版本mysqlclient 1.3.13及以上]
-
安装前验证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
-
安装 mysqlclient:sudo pip install mysqlclient
-
如果出现以下错误:无法执行'x86_64-linux-gnu-gcc': No such file or directory requires sudo apt-get install gcc on the Linux terminal
2.使用pymysql
- 使用 pip install pymysql 安装 pymysql
3.对比:mysqlclient是一个C扩展类,安装麻烦,运行速度快。 pymysql是一个纯python实现,安装简单,运行速度比mysqlclient快
-
为项目创建数据库
-
进入mysql数据库执行:
-
创建数据库数据库名默认字符集utf8 #创建数据库设置默认编码格式为utf8
-
通常数据库名与项目名相同
-
在设置。在 py 文件中配置数据库
-
修改DATABASES配置项内容将sqlite3改为mysql
数据库 u003d {
“默认”:{
'ENGINE': 'django.db.backends.mysql', #指定数据库的存储引擎
'NAME': 'mysql_demo', #指定要连接的数据库名称
'USER': 'root', #指定登录数据库的用户名
'PASSWORD': 'mysql', #数据库登录密码
'HOST': '127.0.0.1', #IP 连接数据库
'PORT': '3306', #连接数据库的端口
}
}
引擎:其他常见的引擎有:
'django.db.backends.mysql'
'django.db.backends.sqlite3'
'django.db.backends.oracle'
'django.db.backends.postgresql'
5.2 模型类
-
型号
-
定义:是一个python类,由django定义。 D b。楷模。从Model派生的子类(即必须继承到django.db.models.Model)
-
一个模型类代表一个数据库的数据表
-
模型类中的每个类属性代表数据库中的一个字段
-
模型是数据库交互的接口,是表示和操作数据库的一种方式
5.3 ORM框架
-
定义:ORM(object relational mapping)对象关系映射,一种允许使用类和对象对数据库进行操作的过程技术,避免使用sql语句对数据库进行操作
-
效果:
1.建立模型类和表之间的对应关系,可以让我们以面向对象的方式操作数据库
2.根据设计的模型类在数据库中生成表
3.可以通过简单的配置切换数据库(切换settings.py文件中配置的数据库名称)
-
优势:
-
只需要面向对象的编程,不需要面向数据库的编码
-
对数据库的操作转换为对类属性和方法的操作
-
无需为各种数据库编写sql语句
-
实现了数据模型与数据库的解耦,屏蔽了不同数据库操作之间的差异。
-
不关注的数据库是mysql、oracle等数据库的内部细节...
-
通过简单的配置,无需修改代码即可轻松更改数据库
-
缺点:
-
对于复杂的业务,成本高(对于查询复杂的业务,需要学习如何使用ORM)
-
根据对象的操作转换为sql语句,根据查询的结果转换为对象会导致映射时的性能损失
-
ORM图

- 型号示例:
1.在子应用的模型类中添加模型类和字段
从 django.db 导入模型
在此处创建模型。
类书(模型。模型):
book_name u003d models.CharField(verbose_nameu003d'Title',max_lengthu003d50,defaultu003d'')
price u003d models.DecimalField(verbose_nameu003d'Price',max_digitsu003d7,decimal_placesu003d2)
- 数据库迁移
-
迁移是django如何同步对模型所做的更改(添加字段、删除模型等)到数据库
-
生成迁移文件 - 执行 Python 管理。 Py makemigrations 将应用下面的模型。 py文件生成中间文件,保存在migrations文件夹中
-
执行迁移脚本程序——python manage.py migrate 执行Migrator进行迁移,将各个应用下的migrations目录中的中间文件同步到数据库中
-
迁移生成的数据库表的名称为:应用程序名_模型类类名
-
创建模型类的过程总结
1.创建应用程序
- 申请中的模型。在 py 文件中编写模型类
从 django.db 导入模型
类模型名称(模型。模型):
FieldName u003d models.FieldType(field-options)
"""
FieldName:字段名,对应迁移后数据表中的字段名
FieldType:字段类型
field-options:字段选项
"""
3.迁移同步makemigrations&migrate
注意:对表结构的任何修改都必须对相应的模型类进行。向模型类添加字段时需要设置默认值。
- 字段类型
字段类型
数据库类型
影响
范围
布尔字段()
微小的(1)
使用 True 或 False 来表示值
-
字符字段()
varchar
-
max_length:字符的最大长度(必填参数)
日期字段()
日期
表示日期
auto_now:每次保存对象时,
自动将字段设置为当前时间(真/假);
auto_now_add:首次创建对象时自动设置当前时间(True/False);
default:设置当前默认时间(取值:字符串格式时间,如'2021-7-1')
* 以上三个参数只能选择一个
日期时间字段()
日期时间(6)
表示日期和时间
参数传递日期字段
浮动字段()
双倍的
使用小数表示值
-
十进制字段()
十进制(x,y)
使用小数表示值
max_digits:数字的总长度,
包括小数点后的位数,
该值必须大于或等于小数_places;
decimal_places:小数点后数字的长度(即小数位数)
* 以上两个参数必填
电子邮件字段()
varchar
代表一个邮箱
-
整数字段()
整数
表示一个整数
-
图像场()
varchar(100)
图片保存到数据库的路径
-
文本域()
长文本
表示可变长度的字符数据
-
注:更多字段类型说明参考官方文档
-
字段选项
-
field 选项指定创建列的附加信息;允许多个字段选项以逗号分隔
字段选项
描述
首要的关键
如果设置为True,则该列为主键,如果指定一个字段为主键,则数据库不会创建id字段
空白的
设置为True时,该字段可以为空(在管理后台编辑数据时),设置为False时,必须填写
无效的
当设置为 True 时,这意味着该列值允许为空,默认为 False。如果此项为 False,建议添加 default 选项来设置默认值。
默认
为你所在的列设置默认值,如果字段 nullu003dfalse 建议添加此项
数据库_索引
设置为 True 时,将向列添加索引
独特的
当设置为 True 时,这意味着该字段在数据库中的值必须是唯一的,并且不能重复
分贝_列
指定列名,如果未指定,则指定类属性名作为列名
详细_name
设置要在管理界面中显示的字段名称,如果未设置,则默认为类属性名称
注:更多字段选项解释参考官方文档
-
模型类-元类(控制表相关属性)
-
定义:内部 Meta 类用于为模型分配属性。 Meta 类下有许多内置的类属性,可让您对模型类进行一些控制
-
常见 Meta 类的内置属性:
属性
影响
db_tableu003d'数据表名称'
修改模型中使用的表名,设置完成后立即更新同步数据库
详细_nameu003d'单数名称'
给模型起一个通俗易懂的名字(单数)显示在/admin管理界面
详细_name_pluralu003d'复数'
对象的复数名称,用于在/admin管理界面中显示
-
#file:models.py
从 django.db 导入模型
类书籍(models.Model):
类元:
db_table u003d 'book' #将当前模型类对应的表名改为book
-
ORM基本操作包括数据库增删查验(add:Create,read:Read,update:Update,delete:Delete)
-
ORM CRUD 核心->模型类。经理对象
-
Manager对象:每个继承自models.Model的模型类都有一个继承自它们的对象,称为manager对象
类 MyModel(models.Model):
···
MyModel.objects.create(···) #对象是管理器对象
-
创建数据 -> 通过创建数据对象来创建数据中的每条记录
-
选项 1:MyModel。对象。创建(属性 1 u003d 值 1,属性 2 u003d 值 2)
-
成功:返回创建的数据
-
失败:抛出异常
-
场景二:创建MyModel实例对象并调用save()保存
obj u003d MyModel()
obj.Attribute 1 u003d 值 1
obj.Attribute 2 u003d 值 2
obj.save() #数据在save()执行之前不会提交到数据库
-
django shell:django中提供了一个交互操作项目提交一个django shell,可以在交互模式下用项目项目的代码执行相应的操作。 django shell可以代替view code直接操作注意:当项目代码发生变化时,需要重新进入django shell;进入方式:python manage.py shell
-
Query Data -> 对数据库的查询也需要用到Manager对象(QuerySet对象可以用来展示ORM使用QuerySet objects.query转换成SQL语句的查询方法)
-
通过 MyModel.objects 管理器方法调用查询方法
方法
用法
功能
返回值
全部()
MyModel.objects.all()
查询MyModel表中的所有数据,等于select * from table
QuerySet 容器对象,内部保存 MyModel 实例
<QuerySet [<Book: Book object (1)>, <Book: Book object (3)>]>
价值观
(“第 1 列”,
'第 2 列')
MyModel.objects.values()
查询并返回部分列的数据,相当于select column 1, column 2 from table
QuerySet 容器对象,里面保存着字典,每个代表一个数据;格式为 {'Column 1': Value 1,'Column 2': Value 2}
值_list
(“第 1 列”,
'第 2 列')
MyModel.objects.values_list()
返回元组形式的查询结果,相当于select Column 1, column 2 from xxx
QuerySet容器对象,内部存储元组,将查询到的数据封装成元组,再封装成查询集QuerySet。如果需要提取查询结果,需要使用索引来获取值
订购_by
(“第 1 列”,
'第 2 列')
MyModel.objects.order_by()
与 all() 方法不同的是,它使用 SQL 语句的 ORDER BY 子句根据字段有选择地对查询结果进行排序。默认按升序排序,降序需要在列前加'-'
QuerySet 容器对象,内部保存 MyModel 实例,并按指定字段排序(相当于 MyModel.objects.all())。 Order_ By ('Column 1')
过滤器(条件)
我的模型。对象。过滤器(属性1u003d值1,属性2u003d值2)是多个属性在一起时的关系
返回包含此条件的所有数据集
QuerySet 容器对象,内部保存 MyModel 实例
排除(条件)
我的模型。对象。排除(条件)多个属性在一起时的“和”关系
返回所有不包含此条件的数据集
QuerySet 容器对象,内部保存 MyModel 实例
获取(条件)
我的模型。对象。获取(条件)
返回唯一符合条件的数据,如果查询结果中还有一条数据,则抛出Model。 MultipleObjectsReturned 异常,查询结果若无数据则抛出 Model。不存在异常
QuerySet 容器对象,内部保存 MyModel 实例
-
查询谓词
-
定义:更灵活的条件查询需要查询谓词
-
说明:每个查询谓词都是一个单独的查询函数
-
语法:类属性_u 查询谓词
查询谓词
解释
例子
__精确的
等效匹配
Author.objects.filter(id__exactu003du003d1)
相当于 select * from author where id u003d 1
__包含
包含指定值
Author.objects.filter(name__containsu003d'w')
相当于 select * from author where name like '%w%'
__从...开始
以xxx开头
Author.objects.filter(name__startwithu003d'w')
相当于 select * from author where name like 'w%'
__endwith
以 xxx 结尾
Author.objects.filter(name__endwithu003d'w')
相当于 select * from author where name like '%w'
__gt
大于指定值
Author.objects.filter(年龄__gtu003d50)
等效于 select * from author where age > 50
__gte
大于或等于指定值
Author.objects.filter(年龄__gteu003d50)
相当于 select * from author where age >u003d 50
__lt
小于规定
Author.objects.filter(年龄__ltu003d50)
等效于 select * from author where age < 50
__lte
小于或等于指定值
Author.objects.filter(年龄__lteu003d50)
相当于 select * from author where age <u003d 50
__在
查找数据是否在指定范围内
作者。对象。过滤器(国家_u inu003d['中国','日本','韩国'])
相当于 select * from author where country in ['China','Japan','Korea']
__范围
查找数据是否在指定的区间范围内
Author.objects.filter(年龄__rangeu003d(30,50))
相当于 select * from author where author 介于 35 和 50 之间
-
更多查询谓词参考官方文档
-
ORM更新操作
-
更新单个数据 -> 修改单个实体的某些字段值的步骤
1.勾选->get()修改实体对象
2.更改->按对象。属性修改数据
- 保存->按对象。 save() 保存数据
- 批量更新数据->直接调用QuerySet的更新(propertyu003dvalue)进行批量修改
#示例
#id大于3的所有书籍均以0元定价
书籍 u003d Book.objects.filter(id__gtu003du003d3)
书籍更新(价格u003d0)
-
ORM删除操作
-
单条数据删除:
1.Find->查找查询结果对应的数据对象
2.删除->调用这个数据对象的delete()方法进行删除
尝试:
auth u003d Author.objects.get(idu003d1)
auth.delete()
除了:
print("删除失败")
- 批量数据删除
1.Find->在查询结果中查找所有符合条件的QuerySet查询集合对象
2.删除->调用查询集合对象的delete()方法删除
#删除所有大于等于65的信息
auths u003d Author.objects.filter(年龄__gtu003d65)
this.ceremony()
-
伪删除
-
通常在业务中删除数据并不容易。相反,它是假删除,即在表中添加一个布尔字段(is_active,is_delete),默认为True。删除时,将(is_active, is_delete) 字段值设置为False,表示要删除的数据
-
注意:使用伪删除时,请确保在显示数据的位置添加is_is Active/is_ Filter Query with deleteu003dTrue
-
F 对象
-
定义:一个 F 对象表示有关数据库中记录的字段的信息
-
影响:
-
通常,您对数据库中的字段值进行操作而不获取它们
-
用于类属性(字段)之间的比较
-
语法:
从 django.db.models 导入 F
f('列名')
-
Q 对象
-
作用:用在条件中实现逻辑或|、逻辑非~、逻辑与
-
语法:
从 django.db.models 导入 Q
Q(条件一) | Q(Condition 2) #条件1或2为真
Q(Condition 1) & Q(Condition 2) #条件1和2同时成立
Q(Condition 1) &~ Q(Condition 2) #条件1为真,条件2不成立。
F 和 Q 对象示例链接
-
聚合查询和原生数据库操作
-
聚合查询
-
定义:聚合查询是指对数据表中某个字段的部分或全部数据进行统计查询。查询数据表中某列的平均值、某个值在一次查询中出现的次数等称为聚合查询
-
分类:聚合查询分为整表聚合和组聚合
-
整表聚合:聚合所有数据的集中统计查询
-
常用的聚合函数有 Sum,Avg,Count,Max,Min
-
导入方式:from django.db.models import *
-
语法:Mymodel。对象。聚合(结果变量名称u003d聚合函数('column'))
-
返回结果:结果变量名称和值的字典,格式为:{Result variable name: {Value}
-
分组聚合:通过计算与查询结果中的每个对象关联的对象集合(首先按字段分组)以产生总值(也可以是平均值或总和),为查询集合的每个项目生成的聚合。
-
语法:查询集。注释(结果变量名u003d聚合函数('column'))
-
返回结果:查询集
-
例子:
-
首先使用查询结果 MyModel.objects.values 查找查询将组合在一起的列 MyModel。对象。值(“第 1 列”、“第 2 列”)
-
QuerySet 通过返回结果。 annotate方法分组聚合得到分组结果QuerySet.annotate(结果变量名u003d聚合函数('column'))
从books.models 导入书
从 django.db.models 导入计数
pub_set u003d Book.objects.values('pub')
#Pub_ Set u003d <QuerySet [{pub':'清华大学出版社'}, {pub':'清华大学出版社'}, {pub':'清华大学出版社'}, {pub':'机工业出版社'}, {pub':'机械工业出版社'}, {pub':'清华大学出版社'}]>
pub_count_set u003d pub_set.annotate(mycountu003dCount('pub'))
#pub_count_set u003d <QuerySet [{'pub':'清华大学出版社','mycount':3},{'pub':'机械工业出版社','mycount':2}\ ]>
-
原生数据库操作-raw():django也支持直接sql语句通信数据库不推荐
-
查询:使用 MyModel.objects.raw() 进行数据库查询操作
-
语法:MyModel.objects.raw(sql语句,拼接参数)
-
返回值:RawQuerySet 集合对象[仅支持基本操作,如循环操作]
书籍 u003d models.Book.objects.raw('从书店选择 *_book')
对于书中的书:
打印(书)
-
SQL注入:使用本机语句时要小心SQL注入
-
定义:用户通过数据上传向服务器提交恶意sql语句达到攻击效果
-
案例1:用户在表单框中输入'1 or 1 u003d 1'搜索好友
s1 u003d Book.objects.raw('select * from bookstore_book where id u003d s%'%('1 or 1 u003d 1'))
-
攻击结果:可查询所有用户数据
-
SQL 注入预防:使用 MyModel。对象。 raw中的拼接参数(sql语句,拼接参数),是一个列表,将所有需要拼接的值写入到列表中
-
例子:
s1u003d Book.objects.raw('select * from bookstore_book where id u003d %s',['1 or 1 u003d 1'])
-
原生数据库操作——cursor():django还支持直接sql语句与数据库通信
-
完全跨模型类操作数据库 - 查询/更新/删除
-
使用方法:
1.从django.db导入连接导入游标包
- 使用创建游标类的构造函数创建游标对象,然后使用游标对象。为确保在出现异常时释放游标资源,通常使用 with 语句创建操作
从 django.db 导入连接
使用 connection.cursor() 作为 cur:
cur.execute('SQL语句','拼接参数')
- 示例:
#使用SQL语句将id为10的书的出版商更改为“xxx出版商”
从 django.db 导入连接
使用 connection.cursor() 作为 cur:
cur.execute('更新书店_book set pub u003d "xxx Press" where id u003d 10;')
扩展知识
- 自定义QuerySet中的输出格式:
#Define 在 Book 模型类中:
定义 __str__(自我):
return '%s_%s_%s_%s'%(self.title,self.price,self.pub,self.market_price) #自定义输出格式
#在shell模式下,会得到如下显示
从books.models导入书
a1 u003d Book.objects.all()
a1
<QuerySet[<书:python_20.00_清华大学出版社_25.00>,<书:Django_70.00_清华大学出版社_75.00>,<书:JQuery_90.00\ _机械工业出版社_85.00>, <B Press_65.00>, <Book: HTML5_90.00_清华大学出版社_105.00>]>
数据库操作常见问题汇总
- 问题一:Python管理何时执行。 py makemigrations 遇到以下迁移错误
您正在尝试在没有默认值的情况下添加不可为空的字段“pub”来预订;我们不能这样做(数据库需要一些东西来填充现有的行)。
请选择一个修复:
- 现在提供一次性默认值(将在所有现有行上设置此列的空值)
- 退出,让我在 models.py 中添加一个默认值
选择一个选项:
- 问题分析:
1.在模型类中添加新字段时出现此错误
- 原理是添加新字段后,数据库不知道应该如何将原始数据分配给新字段,所以在添加新字段时,必须添加默认的默认值。
- 问题改进:
1.如果选择选项1)提供一个临时的默认值,这个默认值会被初始化到迁移文件中,不会反映在模型类中。其他人在代码维护的时候会出现黑框,造成一些代码不匹配的现象
- 选择选项 2) 退出生成迁移文件的过程并再次修改模型。 py,添加一个新的defaultu003dxxx默认值(推荐第二种方法)
-
问题2:数据库迁移文件乱七八糟,django_in数据库的migrations表记录了迁移的所有记录。多人协作时,每个人的迁移文件版本不同,提交时迁移文件混乱
-
问题分析:django_数据库中的migrations表记录了所有的migrate记录,项目的每个应用程序中的migrate文件都应该对应起来
-
问题改进(仅限本地测试):
- 删除所有迁移中的所有000?_xxx。 Py(除了 init.py 文件)
2.删除数据库sql>drop database mywebdb;
3.重新创建数据库sql>create database mywebdb default charsetu003dutf8;
- 重新生成迁移中的所有 000?_ Xxx。 Pypython 管理。 Py 迁移
5.重新更新数据库Python管理。 py迁移
6. admin管理后台
6.1 admin配置步骤
-
创建后台管理账号 - 这是管理后台的最高权限账号
-
termin 切换到项目目录执行-> Python管理。 py 创建超级用户
#命令行执行
python manage.py createsuperuser
用户名(留空使用'sixstar'):topgh #在此处输入用户名
邮箱:634890284@qq.com #这里输入邮箱
密码:#这里输入你的密码(如果太简单会提示太简单)
密码(再次):#在此处再次输入您的密码
密码长度太短。密码必须至少包含八个字符。
这个密码太常见了。
密码只包含数字。
绕过密码验证并创建用户? [y/N]: y #绕过密码验证并创建用户
超级用户创建成功。
6.2 注册自定义模型类
- 注册步骤:
1.子应用程序文件夹中的管理员。导入PY文件中注册管理的模型类,如from。模型导入书
-
打电话给管理员。地点。 register方法注册如admin.site.register(自定义模型类)
-
注册后的自定义模型类在admin主页显示

4、点击第二个Books,进入图书管理页面,管理显示的Book信息和定义Book模型类时定义的def_u与(self)方法中的显示样式一致

-
模型管理器类
-
它的作用:向后端管理界面添加新的、易于使用的功能
-
说明:后台管理器继承自 django。贡献。 admin 中的 ModelAdmin 类
-
用法: 1. 子应用程序下的管理员。模型管理器类在 PY 文件中定义。模型管理器类的名称可以自定义,一般对应一个模型。
类 XXXXManager(admin.ModelAdmin):
“自定义模型类属性”
- 绑定寄存器模型管理器和模型类:
从 django.contrib 导入管理员
从 .models 导入 *
admin.site.register(YYYY,XXXXManager) #将YYYY模型类绑定到Manager类XXXManger
- 常见模型管理器类的类属性
类属性
解释
例子
列表_displayu003d[field1,field2...]
用于控制哪些字段会出现在Admin的修改列表页面
list_display u003d ['id','title','pub','price']
列表_display_linksu003d[field1]
控制列表_显示中的字段,可以链接到修改页面,链接默认添加到id
list_display_links u003d ['title']
列表_filteru003d[field1,field2...]
添加过滤器(指定字段作为过滤条件),过滤器会出现在页面右侧
列表_filter u003d ['pub']
搜索_fieldsu003d[field1,field2...]
添加搜索框(指定字段可用于模糊查询)
搜索_fields u003d ['标题']
列表_editableu003d[field1,field2...]
在列表页添加可编辑的字段,必须在list_displaying中添加字段,并且该字段不能在list_display_links中
list_display u003d ['id','title','pub','price']
- 例子
#file:books/admin.py
从 django.contrib 导入管理员
从 django.contrib 导入管理员
从 .models 导入书,作者
admin.site.register(Book) #注册图书模型类
class AuthorManager(admin.ModelAdmin): #自定义作者模型管理器类
list_display u003d ['id','name','age'] #在admin后台修改列表页面显示字段
list_editable u003d ['age'] #年龄字段可以在列表页编辑
类元:
verbose_name u003d 'author' #模型类名在admin中显示
verbose_name_plural u003d verbose_name #同名的简单数和复数
admin.site.register(Author,AuthorManager) #将模型类绑定到模型管理器类并注册
Model Manager类的类属性更多参考官方文档
6.3 关系映射
-
定义:在关系型数据库中,通常不是所有数据都放在同一张表中,不易扩展
-
常见的关系映射有:
1.一对一映射:一人一张身份证
- 一对多映射:一个班级可以有多个学生
3.多对多映射:一个学生可以注册多门课程,一门课程可以有多个学生学习
-
一对一[创建表]:
-
定义:一对一表示真实事物之间的一一对应关系
-
创建语法:OneaToOneField(类名,on_deleteu003dxxx)
类 A(模型。模型):
......
B类(模型。模型):
属性 u003d models.OneToOneField(A, ondeleteu003dxxx)
- on_delete - 外键删除方法
1.models.CASCADE:级联删除; Django 模拟 SQL 约束 ON DELETE CASCADE 的行为,并删除包含 ForeignKey 的对象。
2.models.PROTECT:保护模式;抛出 ProtectedError 以防止删除引用的对象; [相当于mysql默认的RESTRICT]
-
SET_NULL:Null模式,删除时外键字段设置为null,提供blanku003dTrue,nullu003dTrue,定义字段时允许为null
-
SET_DEFAULT:设置默认值。删除时,外键字段设置为默认值,因此在定义外键时必须添加默认值。
更多外键删除参考官方文档
- 例子:
从 django.db 导入模型
类作者(模型。模型):
name u003d models.CharField(verbose_nameu003d'author',max_lengthu003d11)
类 AuthorWife(models.Model):
name u003d models.CharField(verbose_nameu003d'妻子',max_lengthu003d11)
author u003d models.OneToOneField(Author,verbose_nameu003d'妻子的丈夫',on_deleteu003dmodels.CASCADE) #通常,外键属性称为关联模型类名,小写。在数据库中,外键字段名称与类属性名称不同。默认类属性名+''+id为字段名
-
关联模型类名称的外键类属性名称通常为小写。关键字段名也和数据库中的类属性名不同,默认为类属性名+''+id
-
一对一[创建数据]
-
没有外键的模型类创建数据
-
author1 u003d Author.objects.create(name u003d'王先生')
-
带有外键的模型类创建数据
-
wife1 u003d AuthorWife.objects.create(nameu003d'Mrs. Wang', authoru003dauthor1) #用类属性名创建数据,必须传入带有关联外键的实例对象
-
wife1 u003d AuthorWife.objects.create(nameu003d'王太太', author_idu003d1) #直接使用外键字段名,必须传入关联对象对应的主键值
-
一对一[查询数据]
-
正向查询:直接通过外键属性查询[通过有外键的表查询无外键的表]
#通过老婆找作者
从 .models 导入 AuthorWife
妻子 u003d Wife.objects.get(nameu003d'王太太')
print(wife.name,'你的丈夫是',wife.author.name) #wife.author返回与妻子关联的作者对象,调用作者对象的name属性获取对应值
- 反向查询:没有外键属性的一方可以调用反向属性(带外键的模型类名)查询关联的另一方。反向关联属性是一个实例对象。引用类名(小写),例如:Author的反向引用是一个Author对象。妻子';反向引用不存在时触发异常
author1 u003d Author.objects.get(nameu003d'王先生')
author1.wife.name
-
一对多[创建表]
-
定义:表示事物之间存在一对多的对应关系(例如,一所学校对应多个班级,一个班级对应多个学生);一对多需要明确具体角色,在多个表上设置外键
-
语法:
-
当一个A类对象关联多个B类对象时;外键必须指定 on_delete 模式
A 类(模型。模型):#one
···
B类(模型。模型):#many
attribute u003d models.Foreignkey("one"Model class,on_deleteu003dxxx) #on_delete表示删除A时表B对应字段如何处理
- 例子
#file:otm/models.py
从 django.db 导入模型
类发布者(模型。模型):
"""按[1]"""
name u003d models.CharField('Name',max_lengthu003d50,uniqueu003dTrue)
类书(模型。模型):
"""书籍"""
标题 u003d models.CharField('标题',max_lengthu003d50)
出版商 u003d models.ForeignKey(Publisher,on_deleteu003dmodels.CASCADE)
-
一对多[创建数据]
-
在'许多'之前创建'一个'
从 .models 导入 *
pub1 u003d Publisher.objects.create(nameu003d"清华大学出版社")
Book.objects.create(titleu003d"C++",publisheru003dpub1) #用类属性名创建数据需要传入带有关联外键的对象
Book.objects.create(titelu003d"python",publisher_idu003d1) #通过字段名创建关键数据需要传入关联对象的主键值
-
一对多[查询数据]
-
正向查询:直接通过外键属性查询[通过有外键的表查询无外键的表]
#通过Book查询发布者
abook u003d Book.objects.get(idu003d1)
print(a book.title,'出版商是',a book.publisher.name) #abook.publisher返回abook关联的出版商对象,直接调用出版商对象的name属性
- 反向查询:没有外键属性的一方可以调用反向属性(带外键(小写)_设置的模型类名)向关联的另一方查询
pub1 u003d Publisher.objects.get(nameu003d'清华大学出版社')
books u003d pub1.book_set.all() #通过book_set获取pub1对应的多个Book数据对象,pub.book_set获取RelatedManager关联管理器对象
#books u003d Book.objects.filter(Publisheru003dpub1) #也可以这样获取
print("清华大学出版社出版的书籍有:")
对于书中的书:
打印(书名)
-
多对多[创建表]
-
定义:多对多对象之间的多对多复杂关系,如:一个学生可以报多门课程,一门课程可以对应多于一个学生
-
执行:
-
MySQL中创建多对多依赖第三张表
-
django 不需要手动创建第三张表,django 会自动创建
-
语法:给任意两个关联类添加多对多属性(为便于记忆,属性名可以是关联模型类小写的复数形式)
属性名称u003d models.ManyToManyField(MyModel) #MyModel: 多对多关联模型类
- 例子
#为多个作者创建一本书,为多本书创建一个作者
类作者(模型。模型):
"""作者模型类"""
name u003d models.CharField('writer',max_lengthu003d20)
定义 __str__(自我):
返回 self.name
类书(模型。模型):
"""图书模型课"""
标题 u003d models.CharField('标题',max_lengthu003d20)
authors u003d models.ManyToManyField(Author) #在任意模型类中设置多对多属性
定义 __str__(自我):
返回 self.title
-
多对多[创建数据]
-
场景一:先创建一个没有多对多属性的表,然后关联创建一个多对多属性的表,使用反向属性创建一个多对多属性的表
author1 u003d Author.objects.create(nameu003d'王先生')
author2 u003d Author.objects.create(nameu003d'李小姐')
#先生王和李老师一起写了一本书,蟒蛇
book1 u003d author1.book_set.create(titleu003d'python')
author2.book_set.add(book1) #添加一个obj
- 场景二:创建具有多对多属性的表,关联没有多对多属性的表
book u003d Book.objects.create(titleu003d'python1')
#郭老师和李老师都参与了python1的创作
author3 u003d book.authors.create(nameu003d'郭先生')
book.authors.add(author1)
-
多对多[查询数据]
-
正向查询:具有多对多属性的对象查询对方,其中多对多属性等价于对象
book.authors.all() -> 获取 book 对应的所有作者信息
book.authors.filter(age__gtu003d80) -> 获取80岁以上作者的图书通讯作者信息
- 反向查询:没有多对多属性的对象查询有一侧多对多属性,类名有多对多属性(小写)使用反向属性集
作者.book_set.all()
作者.book_set.filter()
七。会话维护
-
对话
-
定义:从打开浏览器到访问网站到关闭浏览器到结束访问,称为会话
-
HTTP协议是无状态的,难以维护会话状态
-
Cookies和Session是为维护会话状态而生的两种存储技术
7.1 饼干
-
cookies定义:是为了节省客户端浏览器上的存储空间
-
Cookies 功能
-
cookie在浏览器上存储为键值对,键值存储为ASCII字符串(不是中文字符串)
-
存储的数据有生命周期
-
cookies中的数据被域存储隔离,不同域之间不可访问
-
每次访问此网址时,cookies 的内部数据都会被带到服务器上。如果 cookie 太大,响应速度会变慢。
-
Cookies的使用-存储
-
语法:HttpResponse.set_cookie(key,valueu003d'',max_ageu003dNone,expiresu003dNone)
-
密钥名称:cookie
-
值:cookie 的值
-
max_age:cookie 生命周期,以秒为单位
-
expires:具体过期时间
-
未指定 max\ 时 Age 和 expires 在浏览器关闭时使此数据无效
-
创建一个 cookie 示例:
#将key添加到浏览器作为my_var1,值123,过期时间1小时cookie
response u003d HttpReponse('Name added my_var1 of cookie')
response.set_cookie('may_var1','123',3600)
返回响应
- 修改cookie示例:
#将key添加到浏览器为my_var1,修改值为456,过期时间为2小时
response u003d HttpResponse('修改名 my_var1 的 cookie')
response.set_cookie('may_var1','456',3600*2)
返回响应
-
cookie 使用-删除-获取
-
删除 cookie:通过 HttpResponse.delete_cookie(key)
-
删除指定key的cookie,如果key不存在则不发生任何事情
-
获取cookies:通过request.COOKIES绑定字典(dict)从客户端获取COKIES数据; value u003d request.COOKIES.get('cookies name','default')#可以通过get()方法获取,也可以通过索引获取
7.2会话
-
定义:会话是重要的数据,它在服务器上开辟一个空间来保存 Browser-Server 交互
-
实现:
-
使用 session 需要在浏览器客户端上启动 cookie 和 cookie 中存储的 session ID
-
每个客户端可以在服务器端有一个单独的会话
-
注:此数据不会在不同请求者之间共享,与请求者一一对应
-
设置。在py中配置session(默认自动配置)
-
将 INSTALLED_ 添加到 APPS 列表中。贡献。会议'
-
添加 ``` 到中间件列表
-
SESSION_COOKIE_AGE:指定 sessionid 将在 cookie 中保存多长时间(默认为 2 周)
-
SESSION\EXPIRE\AT\BROWSER\CLOSE u003dTrue:设置会话在浏览器关闭时过期,默认为False
-
注意:Django 中的 session 数据是存储在数据库中的,所以在使用 session 之前需要确保已经执行了 migrate。 Django 将会话存储在 django_database 会话表中
-
Django 中的会话问题:
-
Django_session表单是表单设计,数据量不断增长[浏览器故意删除了session id,但数据库中的数据没有被删除]
-
可以执行 Python 管理。 py clearsessions 删除过时的会话数据
-
session的使用
-
会话对象是 EssionStore 类型的类字典对象,可以以类字典的方式进行操作
-
会话可以存储为字符串、整数、字典、列表等
-
添加会话到服务器 request.session['KEY']:VALUE
-
获取session的值:value u003d request.session['KEY'];value u003d request.session.get('KEY', default)
-
删除会话:del request.session['KEY']
-
Cookie 与会话
类型
存储位置
安全
目的
饼干
浏览器
相对不安全
常用于存储长期数据
会议
服务器
相对安全
通常用于存储短期数据
7.3缓存
-
缓存
-
定义:缓存是一类可以更快地读取数据的介质的总称。也指其他可以加快数据读取速度的存储方式。它通常用于存储临时数据。通用媒体是快速读取的内存。
-
意义:视图渲染有一定成本,数据库中频繁查询过高;所以对于变化频率较低的页面,可以考虑使用缓存技术来减少实际的渲染时间,让用户得到响应的时间成本更低。
-
案例分析:
从 django.shortcuts 导入渲染
def 索引(请求):
#渲染时间复杂度极高
book_list u003d Book.objects.all() #->假设时间为 2s
return render(request,'index.html',local()) #这里的页面渲染会发生在book_list查询直到结果才执行
- 优化思路:(去官网)
给定一个 URL,尝试在缓存中查找该页面
如果页面在缓存中:
返回缓存页面
其他:
生成页面
将生成的页面保存在缓存中(以备下次使用)
返回生成的页面
- 缓存场景:
1.博客列表页面
- 电商商品详情页
3.场景特征:缓存在哪里,数据变化少
-
在 django 中设置 cache-database 缓存
-
将缓存的数据存储在数据库中
-
注意:虽然存储的媒体没有被替换,但是当一个负责查询的结果直接存储在另一个表中时,比如多条件下的过滤查询结果,可以避免复杂的查询,提高效率。
-
settings.py,添加缓存配置
缓存 u003d {
“默认”:{
'BACKEND':'django.core.cache.backends.db.DatabaseCache', #engine
'LOCATION':'my_cache_table',#设置缓存使用的数据表命名为my_cache_table
'TIMEOUT':300 #设置缓存保存时间,单位为秒,默认300
“选项”:{
'MAX_ENTRIES':300, #缓存的最大数据条数
'CULL_FREQUENCY':2 #达到最大缓存数时删除1/X个缓存条目
}
}
}
-
注:数据库缓存中使用的数据表需要手动创建,python管理在django shell中执行。 py createcachetable,表名设置在CACHES里面
-
My_是数据库迁移后数据库中自动生成的Cache_表数据表,数据表中的字段:
-
cache_key:缓存键
-
值:缓存值
-
expires:缓存过期时间
-
在django中设置Cache-Local Memory Cache
-
数据缓存在服务器内存中
-
配置示例:
缓存 u003d {
“默认”:{
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'unique-snowflake', #Memory 寻址 - 使用雪花算法
}
}
-
在 django 中设置缓存文件系统缓存
-
将缓存数据存储在本地文件中
-
配置示例:
缓存 u003d {
“默认”:{
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': '/var/tmp/django_cache', #缓存文件夹路径
'LOCATION': 'c:\test\cache', #windows下的例子
}
}
-
在django中使用Cache-Whole Cache策略
-
在视图函数中:将整个视图函数缓存在数据库中,如果需要在某个视图中添加缓存,请在该视图上直接使用cache_ 页面装饰器
从 django.views.decorators.cache 导入缓存_page
@cache_page(30) -> Company s,当前视图缓存有效期
def my_view(请求):
···
-
逻辑:视图的整个响应在第一次请求时存储在缓存中,下一个请求检查缓存中是否有需要的响应,如果有则不再在视图函数中处理。
-
在路由中:在需要增加缓存的视图调用位置增加缓存
从 django.views.decorators.cache 导入缓存_page
url 模式 u003d [
path('page/',cache_page(60)(my_view)),#逻辑同尝试函数
]
-
缺点: 1、当整个视图函数被缓存时,下次请求时,缓存不会过期,请求的数据直接进入缓存,如果视图函数有相关权限去查,不验证可能(例如博客网站,博主访问后会将私博客和公开博客一起访问到缓存中,访问者直接访问不会去查看功能验证访问博客的私博客); 2、删除缓存成本太高,不知道缓存的key,不能主动删除,容易导致新旧数据不一致。 (编辑后的数据无法及时更新到缓存中)
-
在django中使用Cache-Local Cache
-
介绍使用缓存 API
-
方式一:使用缓存导入特定对象['CACHE configuration key']
从 django.core.cache 导入缓存
cache1 u003d caches['default'] #默认配置的CACHHES的Key名称->设置文件
cache2 u003d 缓存['myalias']
-
方式二:直接从CACHES配置项中导入'default'项:from django.core.cache import cache
-
缓存API相关方法:
影响
范围
返回值
cache.set(键,值,超时)
存储缓存
Key:缓存键,字符串类型
值:Python 对象
TIMEOUT:缓存存储时间(s),默认为CACHES中的TIMEOUT值
缓存.get(键)
获取缓存
Key:缓存键,字符串类型
缓存.add(键,值)
存储缓存,仅在key不存在时有效
Key:缓存键,字符串类型
值:Python 对象
cache.get_or_set(key,value,timeout)
如果没有可用数据则设置
Key:缓存键,字符串类型
值:Python 对象
TIMEOUT:缓存存储时间(s),默认为CACHES中的TIMEOUT值
cache.set_many(字典,超时)
大容量存储缓存
dict:缓存键和值的字典
timeout:缓存时间(s)
cache.get_many(key_list)
批量获取缓存
key_list:包含键的列表
缓存.删除(键)
删除键的缓存数据
Key:缓存键,字符串类型
cache.delete_many(key)
批量删除缓存
key_list:包含键的列表
-
浏览器缓存策略
-
强缓存:不向服务器发送请求,直接从缓存中读取资源
-
响应头 - 过期
-
定义:缓存过期时间,指定一个资源什么时候过期,是服务器端的一个具体时间点
-
示例:到期时间:2030 年 4 月 2 日星期四 05:14:08 GMT
-
响应头 - 缓存控制
-
作用:在HTTP/1.1中,Cache-Control主要用于控制网页缓存,比如当Cache-Control:max-ageu003d120代表请求创建时间后120秒,缓存失败
-
注意:当前服务器将使用两个标头响应浏览器。浏览器更喜欢 Cache-Control

-
协商缓存 -> 源自强缓存
-
强缓存中的数据一旦过期,还需要与服务器通信以获取最新数据。当强缓存数据是静态文件、大图片等带宽密集且难以更改的数据时,浏览器会与服务器协商当前缓存是否可用。如果可用,服务器不必返回数据。浏览器会继续使用之前缓存的数据,如果文件不可用,则返回最新数据。
-
响应头:Last-Modified 和 If-Modified-Since 请求头
-
解释:
- Last-Modified 是文件的最新修改时间。当浏览器第一次请求静态文件时,服务器返回 Last-Modified 响应头,代表资源需要协商的缓存
2.缓存过期时,浏览器使用获取到的Last-Modified值作为请求头If-Modifield-Since的值,与服务器协商发送请求,服务器返回304响应码[空响应体],表示缓存继续使用,200响应码表示缓存不可用[响应体为最新资源]
-
缺点:不够准确,Last-Modified是根据修改时间以秒为单位判断缓存是否可以继续使用;如果文件被修改了很短的时间,Last-Modified 无法发现文件已更改
-
响应头 ETag 响应头和 If-None-Match 请求头
-
解释:
-
ETag是唯一标识符(由服务器生成),当服务器响应请求时返回当前资源文件,每当资源发生变化时重新生成(唯一标识为哈希值)。
-
当缓存过期时,浏览器使用ETag响应头的值作为If-None-Match请求头的值向服务器发送协商请求。服务器收到请求头后,比较文件标识,不一致则认为资源不可用,返回200响应码表示缓存不可用[响应体为最新资源],如果不一致则返回304响应码可用的
- 缺点:请求时对文件计算哈希值,会消耗计算资源
8.中间件
8.1中间件定义
-
定义:中间件是django请求/响应处理的钩子框架。它是一个轻量级的低级插件系统,用于全局更改 django 输入或输出
-
中间件表示为一个类
-
每个中间件组件负责一些特定的功能,例如django有一个中间件组件AuthenticationMiddleware,它使用会话将用户与请求关联起来
8.2 中间件使用
-
编写中间件:
-
中间件类必须继承自 django.utils.deprecation.MiddlewareMixin 类
-
一个中间件类必须实现以下五种方法中的一种或多种
-
进程_request(自我,请求):
-
作用:主路由执行前丢弃,每次请求时调用,返回None(请求通过)或HttpResponse对象(请求失败)
-
目的:过滤请求
-
进程_view(self,request,callback,callback_args,callback_kwargs):
-
作用:回调:是一个视图函数; callback_args:视图函数的位置参数,callback_kwargs:视图函数的关键字参数;在调用视图之前调用,在每个请求上,返回 None(请求通过)或 HttpResponse 对象(请求失败)
-
目的:用于代码级替换和过滤,这个方法给你视图函数的参数
-
过程_response(自我,请求,响应):
-
作用:response:是视图函数的响应对象;在所有响应返回到浏览器之前调用,在每个请求上,返回 HttpResponse 对象
-
进程_exception(自我,请求,异常):
-
作用:处理过程中抛出异常时调用,返回一个HttpResponse对象
-
用途:通常用于捕获和发送开发人员发生的异常
-
过程_template_response(自我,请求,响应):
-
作用:当视图函数执行完毕,并且视图函数返回的对象中包含render方法时调用;该方法需要返回一个实现了render方法的响应对象
-
注:中间件中大部分方法返回None,忽略当前操作进入下一个事件,返回HttpResponse对象结束请求,直接返回给客户端
-
注册中间件:
-
在设置。在 py 文件中注册
#file:settings.py
中间件u003d [
···
“我的中间件”,
]
-
注意:配置为列表,调用中间件时,在处理请求视图之前从上到下执行。请求视图处理完毕后,中间件自下而上执行
-
示例:
-
添加过滤请求号中间件
#file:mymiddleware.py
从 django.http 导入 HttpResponse
从 django.utils.deprecation 导入 MiddlewareMixin
进口重新
类 MWare(MiddlewareMixin):
count_dict u003d {} #创建一个统计次数的字典
def 进程_request(自我,请求):
request_ip u003d request.META['REMOTE_ADDR'] #获取请求IP
request\url u003d request.path_info #获取请求地址
if re.match(r'^/test',request_url): #匹配请求是否以/test开头
times u003d self.count_dict.get(request_ip,0) #查询当前IP的请求数,默认0
self.count_dict[request_ip]u003d times + 1 #请求数+1
if times < 5: #如果请求数小于5,请求正常通过
返回
else: #如果请求数大于5,返回HttpResponse,阻塞请求
return HttpResponse("超过 5 次访问,请求失败")
else: #如果不以/test开头,则直接正常通过
返回
- 注册中间件
#file:settings.py
中间件 u003d [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'middleware.mymiddleware.MWare',
]
用django请求流程图

8.3 CSRF - 跨站伪造请求攻击
-
定义:一些恶意网站包含链接、表单按钮或 JavaScript,它们试图使用浏览器中登录用户的身份验证信息在您的网站上执行某些操作。这是跨站点请求伪造(CSRF:Cross-Site-Request-Forgey)
-
CSRF预防:
-
django使用比较'code'机制来防范攻击
-
原则:
-
Cookies存储代码1,模板中的表单包含代码2。用户只在本网站下提交数据,代码2会随着表单提交提交给服务器,django比较两个代码,如果比较成功,则视为合法请求,否则为非法请求 - 403响应码
-
配置步骤:
- 在设置中。在 py 文件中确认 MIDDLEWARE 中的 Django。中间件。 Csrf。 CsrfViewMiddleware 是否打开
2.在模板的form标签下添加如下标签{%csrf_token%}
- 示例:
<!DOCTYPE html>
<HTML浪u003d"恩">
<头部>
<元字符集u003d"UTF-8">
<title>CSRF-TEXT</title>
</head>
<正文>
<form actionu003d"/test_csrf" methodu003d"post">
{% csrf_token %}
<输入类型u003d“文本”名称u003d“测试”>
<input typeu003d"submit" valueu003d"Submit" nameu003d"key">
</form>
</正文>
</html>
-
特别说明(本地开启csrf):
-
如果一个视图不需要 django 进行 csrf 保护,你可以使用一个装饰品来关闭对该视图的检查
-
例子:
从 django.views.decorators.csrf 导入 csrf_exempt
@csrf_exempt #使用装饰器关闭csrf对本次尝试的检查
def my_view(请求):
返回 HttpResponse('hello world')
9.网页的分页功能
-
分页定义
-
定义:分页是指有大量的数据要显示在一个网页上,而每个页面上只显示一部分数据以便于阅读。
-
优点:易读,数据抽取少,服务器压力小
-
django 实现:
-
django 提供 Paginator 类方便分页
-
Paginator 类位于:django.核。在分页器模块中
-
分页器对象
-
功能:负责分页数据的整体管理
-
语法:Paginator u003d Paginator (object_list, per_page)
-
参数:
-
object_list:需要分页数据的对象(或QuerySet对象)的列表
-
per_page: 每页数据条数
-
返回值:
-
分页器的对象
-
Paginator 对象的属性:
-
count:需要分页数据的对象总数
-
num_pages:分页后的总页数
-
page_range:从1开始的范围对象,记录当前页数
-
per_page:每页显示的数据数
-
Paginator 对象的方法
-
分页器对象。页码(编号):
-
参数编号为页码信息(从1开始)
-
返回当前编号页对应的页信息
-
如果提供的页面不存在,则抛出 InvalidPage 异常
-
无效页面异常
-
总异常基类,包含以下两个异常子类
-
PageNotAnInteger:当传入page()的数字不是整数值时抛出
-
EmptyPage:当传递给 page() 的数字是有效值但该页面上没有对象时抛出
-
页面对象
-
定义:负责管理特定页面上的数据
-
语法:分页器对象的page()方法返回页面对象
-
页面 u003d 分页器。页码(页码)
-
属性:
-
object_list:当前页面所有数据对象的列表
-
number:当前页面的编号,从1开始
-
paginator:与当前页面对象关联的分页器对象(查看哪个分页器对象生成了页面对象)
-
has_next():如果有下一页则返回True
-
has_previous():如果有上一页,则返回True
-
has_other_pages():如果有上一页或下一页则返回True
-
next_page_number():返回下一页的页码,如果下一页不存在则抛出InvalidPage异常
-
previous_page_number():返回上一页的页码,如果上一页不存在则抛出InvalidPage异常
-
示例
#file:urls.py
从 django.urls 导入路径
从 .导入视图
url 模式 u003d [
path('test_page', views.test_page), #创建路由
]
#file:views.py
def 测试_page(请求):
#请求来自 URL 的页码
p u003d request.GET.get('page',1)
data_list u003d [str(i) for i in range(20)] #生成列表数据
#创建分页器对象
分页器 u003d 分页器(数据\列表,每页u003d2)
#创建页面对象
page u003d paginator.page(int(p))
返回渲染(请求,'test_page.html',locals())
<!--file:text_page.html-->
<!DOCTYPE html>
<HTML浪u003d"恩">
<头部>
<元字符集u003d"UTF-8">
<title>分页显示</title>
</head>
<正文>
{% for p in page.object_list %} <!--from page 获取对象中当前页面的数据-->
{{ p }}
{% endfor %}
{% if page.has_previous %}
<a hrefu003d"/test\page?pageu003d{{ page.previous\page\number }}">上一页</a>
{% 其他 %}
<p>上一页</p>
{% endif %}
{% for pg in paginator.page_range %}
{% if pg u003du003d page.number %}
{{ pg }}
{% 其他 %}
<a hrefu003d"test_page?pageu003d{{ pg }}">{{ pg }}</a>
{% endif %}
{% endfor %}
{% if page.has_next %}
<a hrefu003d"/test\page?pageu003d{{ page.next_page_ number }}">下一页</a>
{% 其他 %}
<p>下一页</p>
{% endif %}
</正文>
</html>
10.生成 CSV 文件
-
csv文件定义:
-
定义:逗号分隔值,有时也称为字符分割值,因为分割字符也可以是非逗号,它们的文件以纯文本形式存储表格数据(数字和文本)
-
说明:可通过Excel等常用制表工具直接读取
-
在 Python 中生成 csv 文件
-
Python提供了一个内置库,csv;可以直接从此库中操作 csv 文件
-
示例如下:
导入 csv
使用 open('eggs.csv','w',newlineu003d'') 作为 csvfile:
writer u003d csv.writer(csvfile) #创建一个writer对象
writer.writerow(['a','b','c']) #按行写入数据,
-
在 django 中的实现
-
下载网站上的csv文件,注意以下几点
-
响应类型Content-Type类型需要修改为text/csv,告诉浏览器该文档是CSV文件,不是HTML文件(响应类型在HttpResponse对象中修改)
-
响应将获得一个带有 csv 文件名称的附加 Content-Disposition 标头,浏览器将使用该标头打开 Save As @ 对话框
-
案子:
导入 csv
从 django.http 导入 HttpResponse
从 django.shortcuts 导入渲染
从books.models 导入书
def make_csv_view(请求):
response u003d HttpResponse(content_type u003d 'text/csv') #修改内容类型
响应['内容配置'] u003d '附件;文件名 u003d“mybook.csv”'
所有_book u003d Book.objects.all()
writer u003d csv.writer(响应)
writer.writerow(['id','title'])
对于所有_book中的b:
writer.writerow([b.id,b.book_name])
返回响应
11.用户认证系统
-
定义:django自带一个用户认证系统,用于处理用户账户、组、权限和基于cookie的用户会话
-
用户可以直接使用django自带的user表
-
详情参考官方文档
-
基础字段:模型位置:from django.contrib.auth.models import User
场地
类型
无效的
钥匙
默认
额外的
信息
ID
整数(11)
不
在
无效的
自动递增
ID
密码
varchar(128)
不
无效的
密码
上次登录
日期时间(6)
是的
无效的
上次着陆时间
是_超级用户
微小的(1)
不
无效的
是否是管理员帐户 (/admin)
用户名
varchar(150)
不
统一
无效的
用户名
名
varchar(150)
不
无效的
姓名
姓
varchar(150)
不
无效的
姓
电子邮件
varchar(254)
不
无效的
邮箱
是_员工
微小的(1)
不
无效的
我可以访问管理员管理界面吗
活跃
微小的(1)
不
无效的
是否是活跃用户,默认为True,
通常,不会删除用户,而是将用户的 is_active 设置为 False
加入日期
日期时间(6)
不
无效的
用户创建时间
-
模型操作-创建用户
-
创建普通用户
从 django.contrib.auth.models 导入用户
user u003d User.objects.create_user(username, email, password) #用户名,密码为必填项
- 创建超级用户
从 django.contrib.auth.models 导入用户
user u003d User.objects.create_superuser(username, email, password) #用户名,密码为必填项
-
模型操作-删除用户
-
使用伪删除操作:将_active的值改为False
从 django.contrib.auth.models 导入用户
尝试:
user u003d User.objects.get(usernameu003d'用户名')
user.is_active u003d 假
用户.save()
print("成功删除普通用户")
除了:
print("普通用户删除失败")
-
模型操作-校验密码
-
在auth中调用authentication
从 django.contrib.auth 导入验证
用户 u003d 验证(用户名 u003d 用户名,密码 u003d 密码)
-
说明:如果用户名和密码验证成功则返回对应的用户对象,否则返回None
-
模型操作-修改密码
从 django.contrib.auth.models 导入用户
尝试:
user u003d User.objects.get(usernameu003d'用户名')
user.set_password('654321')
用户.save()
return HttpResponse("密码修改成功!")
除了:
return HttpResponse("密码修改失败!")
-
模型操作-登录停留
-
在 auth 中调用 login 进行登录
从 django.contrib.auth 导入登录
def 登录_view(请求):
user u003d authenticate(usernameu003dusername,passwordu003dpassword) #返回选中的用户对象
login(request,user) #传入请求并检查用户对象
-
模型操作-登录状态检查
-
调用 login_in 装饰器 必填,在需要使用装饰方法检查的视图中添加装饰
-
如果需要配置登录检查不成功的跳转页面,需要设置tings。 py文件中的配置:LOGIN_URL u003d'Jump url'
从 django.contrib.auth.decorators 导入登录_required
@login_required #装饰视图必须登录用户才能访问
def 索引_view(请求):
login_user u003d request.user #获取当前登录用户
···
- 模型操作-登录状态取消
从 django.contrib.auth 导入注销
def 注销_view(请求):
logout(request) #直接传入request
-
扩展内置用户表的字段
-
场景1:通过创建新表与内置表进行1对1映射
-
场景二:继承内置的抽象用户模型类,覆盖类属性
-
场景二实施步骤:
-
添加一个新的应用程序
-
定义模型类继承自 AbstractUser
-
在设置。 AUTH_在PY文件中表示 USER_MODEL u003d'应用程序名称。班级名称'
-
注意:这是在第一次迁移执行之前完成的
-
例子:
从 django.db 导入模型
从 django.contrib.auth.models 导入 AbstractUser
class UserInfo(AbstractUser): #Inherited from AbstractUser
phone u003d models.CharField(max_length u003d 11,default u003d '') #新增字段
#file:settings.py
AUTH_USER_MODEL u003d 'user.UserInfo'
添加用户(与原用户相同)
从 user.models 导入 UserInfo
UserInfo.objects.create_user(用户名u003d'xxx',密码u003d'123456',手机u003d'13344445555')
12.文件上传功能
-
定义:用户可以通过浏览器上传图片等文件到网站
-
场景:用户上传头像,处理文件[PDF、TXT等]。
-
上传规则 - 前端 [HTML]
-
文件上传必须提交POST
-
以 <form> 形式上传的文件必须具有 enctypeu003d"multipart/form-data" 才能包含文件内容数据
-
上传表单中带有<input typeu003d"file" nameu003d"xxx">标签的文件
-
上传规则-后端[django]
-
获取上传文件的内容:在视图函数中使用request。 FILES 获取文件框的内容
-
语法:file u003d request.FILES['XXX']
-
解释:
1.FILES键对应页面中文件框的名称值
- File:是一个绑定的文件流对象
3.file.name:获取文件名
4.file.file:文件的字节流数据
5.表单中的文本框内容仍然是请求的。发布删除
-
配置文件的访问和存储路径
-
在设置。在py中设置MEDIA相关的配置; django 将用户上传的文件统称为媒体资源
#file:settings.py
MEDIA_URL u003d '/media/' #配置上传文件的访问路径
MEDIA_ROOT u003d os.path.join(BASE_DIR,'media') #配置文件存储路径
-
手动绑定 MEDIA_ URL 和 MEDIA_ROOT
-
将路线添加到主路线
从 django.conf 导入设置
从 django.conf.urls.static 导入静态
urlpatterns +u003d 静态(settings.MEDIA_URL,document_root u003d settings.MEDIA_ROOT)
-
说明:使用static使MEDIA_URL和MEDIA_ROOT绑定,django收到MEDIA_以URL开头的请求后,去MEDIA_ROOT路径查找资源
-
文件写入方案一:传统打开方式
@csrf_exmpt #取消csrf对以下视图函数的验证
def 上传_view(请求):
如果 request.method u003du003d 'GET':
返回渲染(请求,'test_upload.html')
elif request.method u003du003d 'POST':
a_file u003d request.FILES['myfile'] #获取上传文件的文件流对象
print("上传的文件名是:",a_file.name)
filename u003d os.path.join(settings.MEDIA_ROOT,a_file.name) #j 将上传的文件名与文件存储路径拼接起来
使用 open(filename,'w') 作为 f:
data u003d a_file.file.read() #使用read()方法将a_file.file的字节流数据读出
f.write(data) #写入读取数据
return HttpResponse("接收文件:",a_file.name + "成功")
-
文件编写方案2:diango实现-带ORM
-
用法:借助模型类中的 FileField(uploadu003d'subdirectory name');该字段存储文件的相对路径,如果文件名已经存在,django会自动重命名文件
@csrf_exempt
def 上传_view_dj(请求):
如果 request.method u003du003d 'GET':
返回渲染(请求,'test_upload.html')
elif request.method u003du003d 'POST':
标题 u003d request.POST['标题']
a_file u003d request.FILES['myfile']
Content.objects.create(descu003dtitle,myfileu003da_file) #desc,myfile是Content模型类中的字段名
return HttpResponse("----上传正常----")
- 上传示例:
# 1.file:settings.py,配置MEDIA_ URLs和MEDIA_ROOT
媒体_URL u003d '/媒体/'
MEDIA_ROOT u003d os.path.join(BASE_DIR,'media') #在项目根目录下创建一个media文件夹,存放上传的文件
2.file:urls.py,绑定上传文件的路由和存储目录
从 django.conf.urls.static 导入静态
从 django.urls 导入路径
从测试_上传导入视图
从 django.conf 导入设置
url 模式 u003d [
路径('test_upload',views.upload_view)
]
urlpatterns +u003d 静态(settings.MEDIA_URL,document_root u003d settings.MEDIA_ROOT)
3.file:models.py,创建模型类
从 django.db 导入模型
类测试_upload(models.Model):
title u003d models.CharField(verbose_nameu003d'Title',max_lengthu003d20)
mfile u003d models.FileField(详细_nameu003d'媒体')
4.file:views.py,创建视图函数
从 django.http 导入 HttpResponse
从 django.shortcuts 导入渲染
从 django.views.decorators.csrf 导入 csrf_exempt
从 .models 导入测试_upload
@csrf_exempt
def 上传_view(请求):
如果 request.method u003du003d 'GET':
返回渲染(请求,'test_upload.html')
elif request.method u003du003d 'POST':
标题 u003d request.POST['标题']
m_file u003d request.FILES['myfile']
test\upload.objects.create(titleu003dtitle,m 文件u003dm\file)
return HttpResponse('----文件上传成功----')
<!--5. file:test_upload.html , 配置模板文件-->
<!DOCTYPE html>
<HTML浪u003d"恩">
<头部>
<元字符集u003d"UTF-8">
<title>文件上传</title>
</head>
<正文>
<form actionu003d"test_upload" methodu003d"post" enctypeu003d"multipart/form-data">
<输入类型u003d“文本”名称u003d“标题”>
<输入类型u003d“提交”值u003d“提交”>
<输入类型u003d“文件”名称u003d“我的文件”>
</form>
</正文>
</html>
13.发送邮件
-
业务场景
-
业务警告(traceback.format_exc())可用于捕获异常)、邮箱验证、密码找回
-
邮件相关协议
-
SMTP
-
全称是“简单邮件传输协议”,即简单邮件传输协议(25端口)
-
功能:是一套将邮件从源地址传送到目的地址的规范。它控制邮件的转发 -> 属于推送协议
-
IMAP
-
全称Internet mail Access protocol,即Interactive Mail Access Protocol,是应用层协议(143端口)
-
功能:用于从远程服务器上的本地邮件客户端(Outlook express、Foxmail 等)访问邮件 -> 是一个拉取协议
POP3
-
全称邮局协议3,邮局协议的第三版,是TCP/IP协议家族的成员(端口110)
-
特点:主要用于支持使用客户端远程管理服务器上的邮件->是一个拉取协议
-
IMAP VS POP3:两者都是负责从邮件服务器下载邮件的下拉协议
-
IMAP 具有摘要浏览功能,可预览部分摘要并下载整条消息
-
IMAP是双向协议,客户端动作可以反馈给服务器
-
POP3 必须下载所有邮件,无汇总功能
-
POP3是单向协议,客户端操作无法同步到服务器
-
django 发送邮件
-
在django中配置邮件功能,主要针对SMTP协议,负责发送邮件
-
原则:
-
授予 django 一个邮箱
-
django 使用此邮箱向收件人发送邮件
-
django.core.mail 封装了电子邮件的自动发送 SMTP 协议
-
授权步骤:
-
登录用于发送邮件的邮箱
-
获取发送邮件的邮箱授权号(IMAP/SMTP、POP3/SMTP都可以)
-
django 中的配置:
#file:settings.py 发送邮件相关配置
EMAIL_BACKEND u003d 'django.core.mail.backends.smtp.EmailBackend' # 发送邮件的引擎
EMAIL_HOST u003d 'smtp.qq.com' # 发送邮件的 SMTP 服务器地址
EMAIL_PORT u003d 25 #SMTP服务的端口号
EMAIL_HOST_USER u003d 'XXXXXXXX@QQ.COM' #发送邮件的邮箱账号
EMAIL_HOST_PASSWORD u003d '********' #第三方登录邮箱的授权号
EMAIL_USE_TLS u003d False #与SMTP服务器通信时是否启动TLS链接(安全链接)默认为False
- 函数调用
从 django.core 导入邮件
邮件.发送_mail(
主题,#Mail 主题
消息,#Mail 内容
from_email, #Sender [当前配置的邮箱]
收件人_listu003d['xxxxx@qq.com','xxxxx@163.com'],#邮件收件人列表
)
14.项目部署
-
基本概念:项目部署是指在软件开发完成后,将开发机上运行的软件实际安装到服务器上,以便长期运行
-
部署步骤
1、在安装机上安装并配置相同版本的环境(Python、数据库等)
2.django项目迁移
sudo scp/home/path1 mysite1 root@xx.xx.xx.xx:/home/root/path2path1是本地项目路径,path2是迁移到服务器时存放的路径
3.用uWSGI代替Python管理。 py runserver 方法启动服务器
4.配置nginx反向代理服务器
5.用nginx配置静态文件路径,解决静态文件路径问题
-
uWSGI
-
定义:是WSGI的一种。它实现了http协议、WSGI协议和uwsgi协议。 UWSGI功能齐全,支持很多协议,主要是学习配置
-
uWSGI 安装:ubuntu 执行 sudo PIP install uWSGIu003du003d2.0。 18-i https://pypi.tuna.tsinghua.edu.cn/simple/
-
检查是否安装成功:sudo PIP freeze | grep -i'uwsgi'如果安装成功,会显示对应的版本
-
配置uWSGI
-
添加配置文件:同名项目文件夹/uwsgi.ini; mysite1/mysite1/uwsgi.ini;当您处理正式项目时,此配置文件的名称通常与项目名称相同。初始化
#file:uwsgi.ini
[uwsgi] #文件开头的第一行必须写这个
socket u003d 127.0.0.1:8000 #socket模式的IP地址:端口号,这个模式必须有nginx
http u003d 127.0.0.1:8000 #http通信的IP地址:端口号
chdir u003d /home/···/my_project #项目当前工作目录
wsgi-file u003d my_project/wsgi.py #WSGI 在项目中。 PY 文件的目录,相对于当前工作目录; my_project 是项目目录下的同名文件夹
process u003d 4 #进程数
threads u003d 2 #每个进程的线程数
pidfile u003d uwsgi.pid #pid->主进程的ID。当 uwsgi 启动时,pid 被写入一个文件。 pidfile 指示文件的位置。启动后在boot目录下生成一个uwsgi。 pid文件
daemonize u003d uwsgi.log #服务日志文件的位置,后台启动,将日志文件输出到启动目录下的uwsgi。日志
master u003d True #开启主城管模式
-
特别说明:django 中的设置。 py需要配置如下
-
将DEBUG u003d True修改为DEBUG u003d False #避免向用户导出错误信息
-
将 ALLOWED_HOST u003d [] 改为 ALLOWED_HOSTS u003d ['公有域名'] 或 ['用于服务监控的IP地址']
-
启动uwsgi:切换到uWSGI配置文件所在目录执行uwsgi --ini uwsgi.ini'-ini'是初始化uwsgi
-
stop uwsgi:切换到uWSGI配置文件所在目录执行uwsgi --stop uwsgi.pid
-
查看是否启动成功:ps aux|grep'uwsgi'查看是否启动了一个进程,是启动还是关闭,需要执行这个命令来确认是否和预期的一样
-
注意:启动成功后,进程在后台执行,所有日志输出到配置文件所在目录下的uwsgi。日志; Django 中的任何代码更改都需要重新启动 uwsgi
-
uWSGI 常见问题汇总
问题
原因
解决方案
启动失败
端口占用,其他进程占用uWSGI启动端口
执行 sudo lsof -i: 端口号查询具体进程;执行 sudo kill -9 端口号,杀死进程,重启uWSGI
停止失败
重复的uWSGI启动导致pid文件中的进程号错位
ps out uWSGI 进程,手动kill
-
Nginx
-
定义:nginx是一个轻量级、高性能的web服务器,提供了一系列重要的特性,如http代理和反向代理、负载均衡等。用c语言编写,效率高
-
影响:
-
负载均衡,多台服务器轮流处理请求
-
反向代理:nginx反向代理可以使用uwsgi协议和http协议转发到uWSGI
-
引入正向和反向代理
-
Forward Proxy:代理的对象是客户端,隐藏真正的客户端,服务器不知道真正的客户端是谁
-
反向代理:代理的对象是服务器,隐藏真实服务器,客户端不知道真实服务器是谁
-
负载均衡:nginx均衡请求,将请求分发到多台服务器上进行处理
-
原理:客户端请求nginx,nginx将请求转发给运行uWSGI的django
-
安装:sudo apt install nginx(改国内源:vim/etc/apt/sources.list 改国内源sudo apt-get update)->安装后在ubuntu终端输入nginx -v会显示对应的版本号nginx;安装后nginx会自动启动,占用80个端口
-
配置:修改nginx的配置文件:/etc/nginx/sites-enabled/default;须藤 VIM 默认
服务器{
位置 / {
首先尝试将请求作为文件服务,然后
作为目录,然后回退到显示 404。
尝试_files $uri $uri/ u003d404; # nginx可以通过请求路由自动查找HTML文件。查找html文件的默认目录是root/var/www/html,找不到会报404错误
uwsgi_pass 127.0.0.1:8000; #所有以'/'开头的路由都重定向到127.0. 0.1 的 8000 端口,
包括 /etc/nginx/uwsgi_params; #如果要使用uwsgi协议,必须将所有参数传给uwsgi
}
}
- 启动/停止 nginx
*须藤/等/初始化。 D/nginx/start|stop|restart|status 或
-
sudo service nginx 启动|停止|重启|状态
-
开始:开始,停止:停止,重新开始:重新开始
-
nginx配置每次修改都需要重启,否则配置不生效
-
UWSGI修改配置:nginx负责接收请求并转发给后续的uWSGI,其中uWSGI需要以socket方式启动;
#file:uwsgi.ini
[uwsgi] #文件开头的第一行必须写这个
socket u003d 127.0.0.1:8000 #socket模式的IP地址:端口号,这个模式必须有nginx
http u003d 127.0.0.1:8000 #http通信的IP地址:端口号
-
经常问的问题:
-
检查日志:
-
nginx日志位置:
-
异常日志:/var/log/nginx/error.log
-
正常访问信息:/var/log/nginx/access.log
-
uwsgi日志位置:同名项目目录/uwsgi.log
-
访问 127.0。 0.1:80地址,返回502响应;分析502响应代表nginx反向代理配置成功,但是对应的uWSGI没有启动
-
访问127.0.0.1:80/url,返回404响应: 1.路由确实不在django配置中; 2.nginx配置错误,尝试_not禁止文件
-
静态文件配置
-
原因:有了 nginx 反向代理,django 不再进行静态文件管理。
1.新建路径存放django的所有静态文件/home//////项目名_static/
- django中的设置。向 PY 添加新配置
#file:settings.py
#配置好后django会收集项目名下的静态文件_在静态文件夹下自动新建一个静态文件夹收集静态文件
STATIC_ROOT u003d '/home/···/项目名称_static/static'
3、进入项目根目录,执行Python管理。 py collectstatic 执行此命令后,django会将项目中的所有静态文件收集到STATIC_ROOT,包括django内置的静态文件
- 在 nginx 配置中添加新配置
#file:/etc/nginx/启用站点/默认
添加本地化/静态路由配置并重定向到静态文件存储目录
位置 / 静态 {
根 /home/···/day04_static;
}
-
自定义 404/500 页面
-
将 404 添加到模板文件夹。 HTML模板,当视图触发Http404异常时自动显示; 404.html只在release中有效(即settings.py中的DEBUGu003dFalse),当handler触发Http404异常时跳转到404界面
-
邮箱报警配置
-
作用:当官方服务器上运行的代码出现错误时,可以将错误追踪信息发送到指定邮箱
-
在settings.py - 授权底层邮箱后,添加如下配置
DEBUG u003d False #关闭调试模式
ADMINS u003d [('Recipient Name','Recipient Mailbox'),('Recipient 2 Name','Recipient 2 Mailbox')] #错误报告接收者
SERVER_EMAIL u003d 'email Configured Mailbox' #发送错误报告邮件给发件人,默认为root@localhost账号,大部分邮件服务器拒绝此邮件
-
过滤敏感信息:错误信息中显示错误痕迹,例如密码。 django将配置文件中的敏感信息过滤修改为多个星号,但自定义视图功能需要用户手动过滤敏感信息。可以过滤以下信息(局部变量、POST提交数据)
-
过滤局部变量
从 django.views.decorators.debug 导入敏感_variables
@sensitive_variables('user','pw','cc') #使用装饰器,将过滤后的字段作为参数传递给装饰器
def 进程_info(用户):
pw u003d 用户密码
cc u003d user.credit_card_number
名称 u003d 用户名
- 解释
1、如果错误信息中涉及到局部变量的值,如user,pw,cc,则替换为****,name变量显示真实值
2.顶部需要放置多个装饰器
3.过滤所有局部变量的值而不传参数
- 过滤 POST 数据
从 django.views.decorators.debug 导入敏感_post_parameters
@sensitive_post_parameters('密码','用户名')
def 索引(请求):
s u003d request.POST['用户名'] + request.POST['abcd']
abcd 不存在,导致错误
#POST中的用户名和密码的值将被替换为****
更多推荐

所有评论(0)