Django学习笔记

Django

本篇博客是我的学习笔记,以下内容你是能玩转Django的最精简的基础知识,想要全面了解建议阅读官方文档,官方文档YYDDS。The key of Django


Django常用命令

django-admin startproject 项目名称 创建项目
python manage.py runserver 运行项目
python manage.py runserver 端口号 运行项目时指定运行端口号
Ctrl + C 终止运行项目
python manage.py startapp 应用名 创建应用
python manage.py makemigrations 生成迁移文件
python manage.py migrate 执行迁移,生成表
python manage.py shell进入python终端(通常调试的时候用到)
python manage.py createsuperuser创建超级管理员用户

Django介绍

起源

2005年发布,采用Python语言编写的开源框架。
早期的时候Django主做新闻和内容管理的
重量级的Python Web框架,Django配备了常用的大部分组件

组件

Django包含的组件如下:
基本配置文件/路由系统
模型层(M)/模板层(T)/视图层(V)
Cookies和Session
分页及发邮件
Admin管理后台

用途

用途一:网站/微信公众号/小程序后端开发

用途二:人工智能平台融合

相关文档

Django官网
Django中文文档参考网站

安装

Django与其支持的Python版本:官方文档

Python与Django版本

具体安装操作
以下操作全部都是在你pip能正常使用的前提下,没有更换pip源,建议换个国内源
Windows
用管理员身份打开cmd运行以下命令
安装
pip install django
验证是否安装成功
pip freeze|findstr -i Django
出现以下结果,则安装成功

Linux
打开终端输入以下命令
安装
sudo pip install django
验证安装是否成功
sudo pip freeze|grep -i 'Django'
出现以下结果,则安装成功

离线安装
1、官网下载离线安装包
2、解压安装包
3、进入Django目录
4、执行安装
python setup.py install
5. 检查是否安装成功(方法同上)


Django项目结构

创建项目

成功安装Django后,终端会有django-admin命令
执行 django-admin startproject [项目名] 即可创建出对应项目文件夹
例如:
终端执行 django-admin startproject mySite1 则创建出mySite1项目

启动服务

1.、终端进入到项目文件夹
2、进入到项目文件夹后,执行 python manage.py runserver
启动django服务【注:该启动方式下,Django在前台启动服务,默认监听8000端口】
3、浏览器访问
http://127.0.0.1:8000/
可以看到django的启动页面。【如果想更换端口,则可以用 python manage.py runserver:[端口号]更改】

关闭服务

方式1
在runserver启动终端下执行Ctrl+C可关闭Django服务
方式2
在其他终端下
1、windows执行
netstat -ano|findstr [你的Django端口号]
查询出Django的进程id
linux执行
sudo lsof -i:8000
查询出Django的进程id
2、执行 kill -9 [对应Django进程的id]

启动常见问题

启动报错
Error:That port is already in use
问题原因:端口已被使用,证明当前Django启动时,默认监听的8000端口已被其他进程占用
解决方案:参考更换端口

结构解析

名为mysite1的项目,结构如下

db.sqlite3:创建项目的时候没有,第一次启动服务的时候被创建。Django默认的数据库存储文件。
manage.py:Django所有子命令的入口。例如:
python manage.py runserver启动服务
python manage.py startapp创建应用
python manage.py migrate数据库迁移
......
直接执行python manage.py可列出所有Django子命令
mysite1(项目同名文件夹):
__ init __:Python包的初始化文件
wsgi.py:Web服务网关的配置文件 - Django正式启动时,需要用到。
urls.py:项目的主路由配置 - HTTP请求进入Django时,优先调用该文件。
settings.py:项目的配置文件 - 包含项目启动时需要的配置。


settings.py

配置内容官方文档
settings.py包含了Django项目启动的所有配置项
配置项分为共有配置和自定义配置
配置项格式,例:BASE_DIR = "XXX",其中等号前为全局变量名,必须全部为大写
公有配置 - Django官方提供的基础配置
这些内容我写这篇博客的时候是最新的,以后随着时间的推移可能落时,大家可以到Django官网自行查找。
常见全局变量

  • BASE_DIR = Path(__file__).resolve().parent.parent
    BASE_DIR基础路径,__file__代表的是settings.py文件,那么Path(file).resolve()的结果将会是settings.py文件的绝对路径;然后取其父目录的父目录,也就是django-admin创建项目之后的路径。

  • DEBUG启动模式,取值有两个
      True:调试模式
        调试模式特点:
          1、检测代码改动后,立刻重启服务生效。
          2、提供报错页面
      False:正式启动模式/上线模式

  • ALLOWED_HOSTS过滤请求头Host头
      []空列表,表示只有请求头中host为127.0.0.1,localhost能访问本项目 -DEBUG=True时有效
      ['*']表示任何请求头的host都能访问到当前项目
      ['指定ip','....(ip)']表示只有当前指定host头的值能访问当前项目
      示例:
      如果想要在局域网其他主机也能访问此主机
      python manage.py runserver 0.0.0.0:5000
      指定网络设备如果内网环境下其他主机想正常访问该站点需要添加如下配置项
      ALLOWED_HOSTS=["服务器内网IP"]

  • ROOT_URLCONF表示Django主路由配置文件

  • DATABASESDjango数据库配置文件

  • LANGUAGE_CODEDjango语言配置
      英文:en-us
      中文:zh-Hans

  • TIME_ZONEDjango时区配置
      中国时区:Asia/Shanghai

  • INSTALLED_APPS指定当前项目中安装的应用列表

  • MIDDLEWARE用于注册中间件

  • TEMPLATES用于指定模板的配置信息

settings.py 中也可以添加开发人员自定义的配置
配置建议:名字尽量个性化(以防止覆盖掉公有配置),例如: ALIPAY_KEY = ''XXXX
settings.py 中的所有配置项,都可以按需地在代码中引入
引入方式:
from django.conf import settings


url和视图函数

URL-结构

定义
即统一资源定位符 Uniform Resource Locator
作用:
用来表示互联网上某个资源的地址
URL的一般语法格式为:(注:[]代表其中的内容可省略)
protocol://hostname[:port]/path[?query][#fragment]
[?query]查询字符串
[#fragment]锚点,快速定位。
例如:
http://tts.tmooc.cn/video/showVideo?menuld=657421&version=Aid999#subject
protocol(协议):
http通过HTTP协议访问该资源。格式:http://
https通过安全的HTTPS协议访问该资源。格式:https://
file资源是本地计算机上的文件。格式:file://
hostname(主机名):
是指存放资源的服务器的域名系统(DNS)主机名、域名或IP地址
port(端口号)
整数,可选,省略时使用方案的默认端口
各种传输协议都有默认的端口号
path(路由地址)
由零或多个“/”符号隔开的字符串,一般用来表示主机上的一个目录或文件地址。路由地址决定了服务器端如何处理这个请求。
query(查询)
可选,用于给动态网页传递参数,可有多个参数,用"&"符号隔开,每个参数的名和值用“=”符号隔开。
fragment(信息片段)
字符串,用于指定网络资源中的片段。例如,一个网页中有多个名词解释,可使用fragment直接定位到某一名词解释。

处理URL请求

浏览器 地址栏 -> http://127.0.0.1:8000/page/2003/(网站地址)
  1、Django从配置文件中根据ROOT_URLCONF找到主路由文件;默认情况下,该文件在项目同名目录下的urls;例如mysite1/mysite1/urls.py
  2、Django加载主路由文件中的urlpatterns变量[包含很多路由的数组]
  3、依次匹配urlpatterns中的path,匹配到第一个合适的中断后续匹配。
  4、匹配成功-调用对应的视图函数处理请求,返回响应
  5、匹配失败-返回404响应

如下图中所示,引号括起来的是路由地址,逗号隔开的不带引号的部分是相应的视图函数
urls.py样例
from django.contrib import admin from django.urls import path from . import views urlpatterns = [ path('admin/', admin.site.urls), path("page/2003",views.page_2003_view), #path("page/1",views.page1), #path("page/2",views.page2 ), path("page/<int:pg>",views.pagen_view), path("test_request",views.test_request) ]

视图函数

视图函数是用于接受一个浏览器请求(HttpRequest对象)并通过HttpResponse对象返回响应的函数。此函数可以接收浏览器请求并根据业务逻辑返回相应的响应内容给浏览器.
语法
def xxx_view[函数名](request,[其他参数,....]): return HttpResponse
例如:

file(文件位置):<项目同名文件夹下>/views.py


路由配置

路由配置

settings.py中的ROOT_URLCONF制定了主路由配置列表urlpatterns的文件位置
file(文件位置):<项目同名文件夹下>/urls.py

路由配置-path

path()函数
导入 - from django.urls import path
语法 - path(route,views,name=None)
参数:
1、route:字符串类型,匹配的请求路径
2、views:指定路径所对应的视图处理函数的名称
3、name:为地址起别名,在模板中地址反向解析时使用
例如:
path("page/2003",views.page_2003_view)

路由配置 - path - 转换器

path转换器
语法:<转换器类型:自定义名>
作用:若转换器类型匹配到对应类型的数据,则将数据按照关键字传参的方式传递给视图函数
例如: path('page/<int:page>',views.xxx)
常见转换器类型


re_path()

re_path()函数
在url的匹配过程中可以使用正则表达式进行精准匹配
语法:
re_path(reg,view,name=xxx)
正则表达式命名分组模式(?P<name>pattern);匹配提取参数后用关键字传参方式传递给视图函数
正则表达式
样例:


请求响应

定义

请求是指浏览器端通过HTTP协议发送给服务器端的数据
响应是指服务器端接收到请求后做相应的处理后在回复给浏览器端的数据

请求

样例

请求中的方法

  • 根据HTTP标准,HTTP请求可以使用多种请求方法。
  • HTTP1.0定义了三种请求方法:GET、POST和HEAD(最常用)
  • HTTP1.1新增了五种请求方法:OPTIONS、PUT、DELETE、TRACE和CONNECT

Django中的请求

  • 请求在Django中实则就是视图函数的第一个参数,即HttpRequest对象
  • Django接收到http协议的请求后,会根据请求数据报文创建HttpRequest对象
  • HttpRequest对象通过属性描述了请求的所有相关信息

HttpRequest常见属性:

  • path_info:URL字符串
  • method:字符串,表示HTTP请求方法,常用值:'GET'、'POST'
  • GET:QueryDict查询字典的对象,包含get请求方式的所有数据
  • POST:QueryDict查询字典的对象,包含post请求方式的所有数据
  • FILES:类似于字典的对象,包含所有的上传文件信息。
  • COOKIES:Python字典,包含所有的cookie,键和值都为字符串
  • session:类似于字典的对象,表示当前的会话
  • body:字符串,请求体的内容(POST或PUT)
  • scheme:请求协议('http'/'https')
  • request.get_full_path():请求的完整路径
  • request.MATE:请求中的元数据(消息头)
    • request.MATE['REMOTE_ADDR']:客户端IP地址

以下方法,可以将上面介绍的属性打出来

def test_request(request):
    print("path info is ",request.path_info)
    print("method is",request.method)
    print("Get info is ",request.GET)
    print("full path is ",request.get_full_path)
    return  HttpResponse("test request is OK")

响应

响应示例

常见的HTTP状态码(HTTP Status Code):

-200-请求成功
-301-永久重定向-资源(网页等)被永久转移到其他URL
-302-临时重定向
-404-请求的资源(网页等)不存在
-500-内部服务器错误

状态码规律
HTTP状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字没有分类的作用。HTTP状态码共分为5种类型:

Django中的响应对象
构造函数格式:
HttpResponse(content=响应体,content_type=响应体数据类型,status=状态码)
作用:
向客户端浏览器返回响应,同时携带响应体内容
常用的Content-Type如下:
-'text/html'(默认的,html文件)
-'text/plain'(纯文本的)
-'text/css'(css文件)
-'text/javascript'(js文件)
-'multipart/form-data'(文件提交)
-'application/json'(json传输)
-'application/xml'(xml文件)
HttpResponse子类:


GET和POST请求

定义

  • 无论是GET还是POST,统一都由视图函数接收请求,通过判断request.method区分具体的请求动作
  • 样例
      if request.method == 'GET':
          处理GET请求时的业务逻辑
      elif request.method == 'POST':
          处理POST请求的业务逻辑
      else:
          其他请求业务逻辑
    

GET处理

POST处理

  • POST请求动作,一般用于向服务器提交大量/隐私数据
  • 客户端通过表单等POST请求将数据传递给服务器端,如:

  • 服务器端接收参数
    通过request.method来判断是否为POST请求,如:

    使用post方式接收客户端数据

    取消csrf验证,否则Django将会拒绝客户端发来的POST请求,报403响应

  • 取消csrf验证
    *禁止掉settings.py中MIDDLEWARE中的CsrfViewsMiddleWare


Django的设计模式及模板层

MVC和MTV

MVC代表Model-View-Controller(模型-视图-控制器)模式。

  • M模板层(Model),主要用于对数据库层的封装
  • V视图层(View),用于向用户展示结果(WHAT+HOW)
  • C控制(Controller),用于处理请求、获取数据、返回结果(重要)
    作用:降低模块间的耦合度(解耦)

MTV代表Model-Template-View(模型-模板-视图)模式。

  • M模型层(Model)负责与数据库交互
  • T模板层(Template)负责呈现内容到浏览器(HOW)
  • V视图层(View)是核心,负责接受请求、获取数据、返回结果(WHAT)
    作用:降低模块间的耦合度(解耦)

什么是模板

1、 模板是可以根据字典数据动态变化的html网页
2、 模板可以根据视图中传递的字典数据动态生成相应的HTML网页

模板配置

创建模板文件夹<项目名>/templates
在settings.py中TEMPLATES配置项
1、 BACKEND:指定模板引擎
2、 DIRS:模板的搜索目录
3、 APP_DIRS:是否要在应用中的templates文件夹中搜索模板文件
4、 OPTIONS:有关模板的选项
配置项中需要修改部分
设置DIRS-'DIRS':[os.path.join.(BASE_DIR,'templates')],

模板的加载方式

方案1-通过loader获取模板,通过HttpResponse进行响应
在视图函数中

from django.template import loader
    # 1、通过loader加载模板
    t = loader.get_template("模板文件名")
    # 2、将t转换成HTML字符串
    html = t.render(字典数据)
    # 3、用响应对象将转换的字符串内容返回给浏览器
    return HttpResponse(html)

方案2-使用render()直接加载并响应模板
在视图函数中

def test_web(request):
    from django.shortcuts import  render
    return render(request,'模板文件名',字典数据)

视图层与模板层之间的交互

1、 视图函数中可以将Python变量封装到字典中传递到模板
样例:

def xxx_view(request):
    from django.shortcuts import render
    dic = {
        "变量1":"值1",
        "变量2":"值2"
    }
    return render(request,'xxx.html',dic)

2、 模板中,我们可以用{{变量名}}的语法调用视图传进来的变量。通俗讲就是在html界面中直接调用后端传进来的变量。
例如:

模板层-变量和标签

模板的变量

这里对应上面视图层与模板层之间的交互中的两种方法

1、视图函数中可以将Python变量封装到到字典中传递到模板上
样例:

def xxx_view(request):
    from django.shortcuts import render
    dic = {
        "变量1":"值1",
        "变量2":"值2"
    }
    return render(request,'xxx.html',dic)

能传递到模板中的数据类型

  • str-字符串
  • int-整型
  • list-数组
  • tuple-元组
  • dict-字典
  • func-方法
  • obj-类实例化的对象
    2、在模板中使用变量语法
    {{变量名}}
    {{变量名.index}}
    {{变量名.key}}
    {{对象.方法}}
    {{函数名}}

模板标签

作用:将一些服务器的功能嵌入到模板中,例如流程控制等
标签语法

{% 标签 %}
......
{% 结束标签 %}

if标签
语法:

{% if 条件表达式1 %}
......
{% elif 条件表达式2 %}
......
{% elif 条件表达式3 %}
......
{% else %}
...
{% endif %}

注意:
1、if条件表达式里可以用的运算符 ==,!=,<,>,<=,>=,in,not in,is,is not,not,and,or
2、在if标记中使用实际括号是无效的语法。如果您需要它们指示优先级,则应使用嵌套的if标记。
官方文档

for标签
语法:

{% for 变量 in 可迭代对象 %}
...循环语句
{% empty %}
...可迭代对象无数据时填充的语句
{% endfor %}

官方文档
内置变量-forloop
这个forloop内置变量只能写在for循环里,否则就会报错


模板层-过滤器和继承

模板层-过滤器

定义:在变量输出时对变量的值进行处理
作用:可以通过使用过滤器来改变变量的输出显示
语法:{{变量|过滤器1:'参数值1'|过滤器2:'参数值2'...}}
官方文档
常用过滤器:

模板层-继承

定义:模板继承可以使用父模板的内容重用,子模版直接继承父模板的全部内容并可以覆盖父模板中相应的块
语法-父模板中:

  • 定义父模板中的块block标签
  • 标识出哪些在子模块中是允许被修改的
  • block标签:在父模板中定义,可以在子模版中覆盖
    语法-子模版中:
  • 继承模板extends标签(写在模板文件的第一行)
    例如 {% extend 'base.html' %}
    *子模版重写父模板中的内容块
{% block block_name %}
子模板块用来覆盖父模板快中 block_name 块的内容
{% endblock block_name %}

重写的覆盖规则

  • 不重写,将按照父模板的效果显示
  • 重写,将按照重写效果显示
    注意
  • 模板继承时,服务器端的动态内容无法继承
    参考文档

url反向解析

再谈url

代码中url出现的位置
1、模板【html中】
1)、

<a href='url'>超链接</a>
  点击后 页面跳转至url

2)、

<form action='url' method='post'>
  form表单中的数据 用post方法提交至url

2、视图函数中-302跳转 HttpResponseRedirect('url')
将用户地址栏中的地址跳转到url
代码中url书写规范
1、绝对地址
例如:http://127.0.0.1:8000/page/1
2、相对地址
1、'/page/1' - '/'开头的相对地址,浏览器会把当前地址栏里的协议,ip和端口加上这个地址,作为最终访问地址,即如果当前页面地址栏为http://127.0.0.1:8000/page/3;当前相对地址最终结果为http://127.0.0.1:8000 +/page/1
2、'page/1' - 没有“/”开头的相对地址,浏览器会根据当前url的最后一个“/”之前的内容加上该相对地址作为最终访问地址,例如当前地址栏为http://127.0.0.1:8000/topic/detail;则该相对地址最终结果为http://127.0.0.1:8000/topic+page/1

url反向解析

定义:url 反向解析是指在视图或模板中,用path定义的名称来动态查找或计算出相应的路由。
path函数的语法

  • path(route,views,name="别名")
  • path('page',view.page_view,name='page_url')
    根据path中的name=关键字传参给url确定了一个唯一确定的名字,在模板或视图中,可以通过这个名字反向推断出此url信息
    模板中 - 通过url标签实现地址的反向解析
{% url '别名' %}
{% url '别名' '参数值1' '参数值2' %}
For example:
{% url 'pagen' '400' %}
{% url 'person' age='18' name='vh' %}

在视图函数中 -> 可调用django中的reverse方法进行反向解析

def test_reverse(request):
    from django.urls import reverse
    reverse('别名',args=[],kwargs={})
    #例如:
    print(reverse('pagen',args=[300]))
    print(reverse('person',kwargs={'name':'xixi','age':18}))

静态文件

什么是静态文件?
-如:图片,css,js,音频,视频

静态文件配置

静态文件配置-settings.py中
1、配置静态文件的访问路径【该配置默认存在】

  • 通过那个url地址找到静态文件
  • STATIC_URL = '/static/'
  • 说明:
    指定访问静态文件时是需要通过/static/xxxhttp://127.0.0.1:8000/static/xxx[xxx表示具体的静态资源位置]
    2、配置静态文件的存储路径STATICFILES_DIRS
    STATICFILES_DIRS保存的是静态文件在服务器端的存储位置
#file:settings.py
STATICFILES_DIRS = (os.path.join(BASE_DIR,'static'),)
#配置一个参数的时候,逗号一定要带。

静态文件访问

模板中访问静态文件-img标签为例
方案1-直接拼接访问路径

<img src="/static/images/lena.jpg">
<--或者-->
<img src="http://127.0.0.1:8000/static/images/lena.jpg">

方案2-通过{% static %}标签访问静态文件
1、加载static - {% load static %}
2、使用静态资源-{% static '静态资源路径' %}
3、样例

  • <img src="{% static 'images/lena.jpg' %}">

Django应用及分布式路由

应用

什么是应用?

  • 应用在Django项目中是一个独立的业务模块,可以包含自己的路由,视图,模板,模型

创建应用
1、 用manage.py中的子命令startapp创建应用文件夹
python manage.py startapp 应用名
命令执行完成后会出现相应的文件夹,例如创建名为music的应用

2、在settings.pyINSTALLED_APPS列表中配置安装此应用
3、settings.py配置样例

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    #以上内容为django自动配置的内容,不用管
    #下面配置自己创建的应用
    'user',#用户信息模块
    'music',#音乐模块
    
]

分布式路由

Django中,主路由配置文件(urls.py)可以不处理用户具体路由,主路由的配置文件可以做请求的分发(分布式请求处理)。具体的请求可以由各自的应用来进行处理。

配置分布式路由
1、主路由中调用include函数
语法:include('app名字.url模块名')
作用:用于将当前路由转到各个应用的路由配置文件的urlpatterns进行分布式处理
http://127.0.0.1:8000/music/index为例

from    . import views
from django.urls import include
urlpatterns = [
    path('admin/', admin.site.urls),
    path('music/',include('music.urls'))
]

2、应用下配置urls.py
应用下手动创建urls.py文件,变量内容结构(具体的路由规则根据实际需求编写)同主路由完全一样.
应用的路由已经有主路由配置,所以这里的路由只需要配置应用内路由即可。
例如,完整的地址是:http://127.0.0.1:8000/music/index
主路由配置到http://127.0.0.1:8000/music,子路由配置到:/index

应用下的模板

应用内部可以配置模板目录
1、应用文件夹下手动创建templates文件夹
2、settings.py中开启应用模板功能
TEMPLATE配置项中的'APP_DIRS'值为True即可
应用下templates和外层templates都存在时,django的查找模板规则:
1、优先查找外层templates目录下的模板
2、按INSTALLED_APPS配置下的应用顺序逐层查找
这里有个问题,比如主页文件index.html之前的应用的模板文件夹也有,根据上面的匹配规则不就产生歧义,不能准确的找到我们需要的文件了吗?
解决办法是在应用的templates模板文件夹下创建一个与应用同名的文件夹,将模板文件放在此文件夹下。


模型层及ORM介绍

模型层

模型层-定义

  • 回顾Django MTV

    ![](https://img2022.cnblogs.com/blog/1759058/202207/1759058-20220724194748984-626946983.png)
    
  • 模型层-负责跟数据库之间进行通信

Django配置mysql

  • 安装 mysqlclient[Django 需要 mysqlclient 1.4.0 或更高版本。目前(2022.07.25)mysqlclient官方最高版本为2.1.1]
    Django官方文档关于mysql连接部分
    mysqlclient官方界面

  • Linux(ubuntu):
    1、安装前确认ubuntu是否已安装python3-devdefault-libmysqlclient-dev
    sudo apt list --installed | grep -E 'libmysqlclient-dev|python3-dev'
    2、若上面命令没有输出如图所示结果,则需要安装

安装命令(Debian系): sudo apt-get install python3-dev default-libmysqlclient-dev build-essential

官方教程

至此相关依赖已解决完,下面正式安装mysqlclient
命令:pip install mysqlclient

Windows:
直接执行:pip install mysqlclient

  • 创建数据库
    进入mysql数据库执行
    create database 数据库名 default charset utf8
    通常数据库名跟项目名保持一致
  • settings.py里进行数据库的配置
    • 修改DATABASES配置项的内容,由sqlite3变为mysql

  • 补充:
    * ENGINE - 指定数据库存储引擎
django.db.backends.mysql
django.db.backends.sqlite3
django.db.backends.oracle
django.db.backends.postgresql
      * NAME - 指定要连接的数据库的名称
      * USER - 指定登录到数据库的用户名
      * PASSWORD - 数据库的密码
      * HOST/PORT - 连接具体数据库的 IP 和 端口

什么是模型

  • 模型是一个Python类,它是由django.db.models.Model派生出的子类
  • 一个模型类代表数据库中的一张数据表
  • 模型类中每一个类属性都代表数据库中的一个字段
  • 模型是数据交互的接口,是表示和操作数据库的方法和方式

ORM框架

定义:ORM(Object Relational Mapping)即对象关系映射,它是一种程序技术,它允许你使用类和对象对数据库进行操作,从而避免通过SQL语句操作数据库
作用:
1、建立模型类和表之间的对应关系,允许我们通过面向对象的方式来操作数据库。
2、根据设计的模型类生成数据库中的表格
3、通过简单的配置就可以进行数据库的切换
优点:
* 只需要面向对象编程,不需要面向数据库编写代码
* 对数据库的操作都转化成对类属性和方法的操作
* 不用编写各种数据库的sql语句
* 实现了数据模型与数据库的解耦,屏蔽了不同数据库操作上的差异.
* 不在关注用的是mysql、oracle......等数据库的内部细节.
* 通过简单的配置就可以轻松更换数据库,而不需要修改代码
缺点:
* 对复杂业务,使用成本较高
* 根据对象的操作转换成SQL语句,根据查询的结果转化成对象,在映射过程中有性能损失。
映射关系:

模型示例

此示例为添加一个bookstore_book数据表来存放图书馆中数目信息
1、添加一个app并注册app
2、添加模型类
模型类代码示例:

# file:bookstore/models.py
from django.db import models

# Create your models here.

class Book(models.Model):
    title = models.CharField("书名",max_length=50,default='')
    price = models.DecimalField("定价",max_digits=7,decimal_places=2,default=0.0)

3、数据库迁移

  • 迁移是Django同步你对模型所做更改(添加字段,删除模型等)到您的数据据库模式的方式
    1、生成迁移文件 - 执行python manage.py makemigrations
    将应用下的models.py文件生成一个中间文件,并保存在migrations文件夹中
    2、执行迁移脚本程序 - 执行python manage.py migrate
    执行迁移程序实现迁移。将每个应用下的migrations目录中的中间文件同步回数据库

模型类 - 创建

from django.db import models

# Create your models here.

class 模型类名(models.Model):
    字段名 = models.字段类型(字段选项)

ORM-基础字段及选项1

ORM框架

映射图

映射图

创建模型类流程

  • 创建应用
  • 在应用下的models.py中编写模型类
from django.db import models

# Create your models here.

class 模型类名(models.Model):
    字段名 = models.字段类型(字段选项)
  • 迁移同步 makemigrations&migrate
    任何关于表结构的修改,务必在对应模型类上修改
    例:为bookstore_book表添加一个名为info的字段varchar(100)
    解决方案:
    1、模型类中添加对应类属性
    2、执行数据库迁移

字段类型

  • BooleanField()
    • 数据库类型:tinyint(1)
    • 编程语言中:使用True或False来表示值
    • 在数据库中:使用1或0来表示具体的值
  • CharField()
    • 数据库类型:varchar
    • 注意:必须要指定max_length参数值。
  • DataField()
    • 数据库类型:date
    • 作用:表示日期
    • 参数:
      1、auto_now每次保存对象时,自动设置该字段为当前时间(取值:True/False)。
      2、auto_now_add当对象第一次被创建时自动设置当前时间(取值:True/False)。
      3、default设置当前时间(取值:字符串格式时间如:'2019-6-1')。
      以上三个参数只能多选一
  • DataTimeFiled()
    • 数据库类型:datetime(6)
    • 作用:表示日期和时间
    • 参数与DateField一样
  • FloatField()
    • 数据库类型:double
    • 编程语言中和数据库中都使用小数表示值
  • DecimalField()
    • 数据库类型:decimal(x,y)
    • 编程语言中:使用小数表示该列的值
    • 在数据库中:使用小数
    • 参数:
      max_digits:位数总数,包括小数点后的位数。该值必须大于等于decimal_places
      decimal_places:小数点后的数字数量
  • EmailField()
    • 数据库类型:varchar
    • 编程语言和数据库中使用字符串
  • IntegerField()
    • 数据库类型:int
    • 编程语言和数据库中使用整数
  • ImageField()
    • 数据库类型:varchar(100)
    • 作用:在数据库中为了保存图片的路径
    • 编程语言和数据库中使用字符串
  • TextField()
    • 数据库类型:longtext
    • 作用:表示不定长的字符数据
  • 官方文档

ORM-基础字段及选项2

模型类定义

from django.db import models

# Create your models here.

class 模型类名(models.Model):
    字段名 = models.字段类型(字段选项)

模型类字段选项

  • 字段选项,指定创建的列的额外的信息
  • 允许出现多个字段选项,多个选项之间使用逗号隔开
  • primary_key
    • 如果设置True,表示该列为主键,如果指定一个字段为主键,则此数据库表不会创建id字段
  • blank
    • 设置为True时,字段可以为空。设置为False时,字段是必须填写的
  • null
    • 如果设置为True表示该列值允许为空。
    • 默认为False,如果此选项为False建议加入default选项来设置默认值
  • default
    • 设置所在列的默认值,如果字段选项null=False建议添加此项
  • db_index
    • 如果设置为True,表示为该列增加索引
  • unique
    • 如果设置为True,表示该字段在数据库中的值必须是唯一(不能重复出现的)
  • db_column
    • 指定列的名称,如果不指定的话则采用属性名作为列名
  • verbose_name
    • 设置此字段在admin界面上的显示名称
      字段选项样例

官方文档
ps:修改过字段选项【添加或更改】均要执行makemigrationsmigrate

模型类-Meta类

定义
使用内部Meta类来给模型赋予属性,Meta类下有很多内建的类属性,可对模型类做一些控制
示例:


ORM-基础操作-创建数据

常见问题处理

  • 问题一:当执行python manage.py makemigrations出现如下迁移错误时的处理方法

错误信息

对应的中文

常见问题处理2

  • 数据库的迁移文件混乱的解决办法
  • 数据库中django_migrations表记录了migrate的'全过程',项目各应用中的migrate文件应与之对应,否则migrate会报错。
  • 解决方案:
    1、删除所有migrations里所有的000?_XXX.py(__init__.py除外)
    2、删除数据库,sql > drop database dbname
    3、重新创建数据库,sql > create database dbname
    4、重新生成migrations里所有的000?_XXXX.py,python manage.py makemigrations
    5、重新更新数据库,python manage.py migrate

ORM-创建数据

ORM-操作
基本操作包括增删改查操作,即(CRUD操作)
CRUD是指在做计算处理时的增加(Create)、读取查询(Read)、更新(Update)和删除(Delete)

ORM CRUD 核心 -> 模型类.管理器对象
管理器对象
每个继承自models.Model的模型类,都会有一个objects对象被同样继承下来。这个对象叫管理器对象。
数据库的增删改查可以通过模型的管理器实现

管理器对象

创建数据
Django ORM 使用一种直观的方式把数据库中的数据表示成Python对象
创建数据中每一条记录就是创建一个数据对象
方案1
MyModel.objects.create(属性1=值1,属性2=值2,......)

  • 成功:返回创建好的实体对象
  • 失败:抛出异常
    方案2
    创建MyModel实例对象,并调用save()进行保存

Django Shell
在Django提供了一个交互式的操作项目叫Django Shell 它能够在交互模式用项目工程的代码执行相应的操作
利用Django Shell可以代替编写view的代码来进行直接操作
ps:项目代码发生变化时,重新进入Django Shell
启动方式:python manage.py shell


ORM-查询操作-1

查询简介

  • 数据库的查询需要使用管理器对象进行
  • 通过MyModel.objects管理器方法调用查询方法

查询方法

查询方法

  • all()方法
    用法:MyModel.objects.all()
    作用:查询MyModel实体中所有的数据,等同于select * from tablename
    返回值:QuerySet容器对象,内部存放MyModel实例

  • 可以在模型类中定义__str__方法,自定义QuerySet中的输出格式
    例如 在Book模型类下定义如下:

则在Django shell 中可得到如下显示输出

  • values('列1','列2',......)
    用法:MyModel.objects.values(...)
    作用:查询部分列的数据并返回,等同于select 列1,列2 from xxx
    返回值:QuerySet
    返回查询结果容器,容器内存字典,每个字典代表一条数据,格式为:{'列1':值1,'列2':值2}

  • values_list('列1','列2',......)
    用法:MyModel.objects.values_list(...)
    作用:返回元组形式的查询结果,等同于select 列1,列2 from xxx
    返回值:QuerySet容器对象,内部存放'元组'
    会将查询出来的数据封装到元组中,再封装到查询集合QuerySet

  • order_by()
    用法:MyModel.objects.order_by('列','列')
    作用:
    与all()方法不同,它会用SQL语句的ORDER BY 子句对查询结果进行根据某个字段选择性的进行排序
    说明:
    默认是按照升序排序,降序排序则需要在列前增加'-'表示


ORM-查询操作-2

条件查询-方法

  • filter(条件)
    语法:MyModel.objects.filter(属性1=值1,属性2=值2)
    作用:返回包含此条件的全部数据集
    返回值:
    QuerySet容器对象,内部存放MyModel实例
    说明:
    当多个属性在一起时为“与”关系
    filter样例

filter样例

  • exclude(条件)
    语法:MyModel.objects.exclude(条件)
    作用:返回不包含此条件的全部的数据集
    示例:
    查询清华大学出版社,定价等于50以外的全部图书

示例

  • get(条件)
    语法:MyModel.objects.get(条件)
    作用:返回满足条件的唯一一条数据
    说明:该方法只能返回一条数据,查询结果多余一条数据则抛出Model.MultipleObjectsReturned异常,查询结果如果没有数据则抛出Model.DoesNotExist异常

查询谓词

定义:做更灵活的条件查询时需要使用查询谓词
说明:每一个查询谓词是一个独立的查询功能
__exact:等值匹配
示例:

查询谓词

__contains:包含指定值
示例:

__startswith:以XXX开始
__endswith:以XXX结束
__gt:大于指定值
样例

样例

__gte:大于等于
__lt:小于
__lte:小于等于
__in:查找数据是否在指定范围内
样例:

样例

__range:查找数据是否在指定的区间范围内
样例:

样例

官方文档


ORM-更新操作

更新单个数据

  • 修改单个实体的某些字段值的步骤:
    1、查
    -通过get()得到要修改的实体对象
    2、改
    -通过对象.属性的方式修改数据
    3、保存
    -通过对象.save()保存数据

批量更新数据

  • 直接调用QuerySetupdate(属性=值)实现批量修改
  • 示例:

批量更新数据


ORM-删除操作

单个数据删除

步骤
1、查找查询结果对应的一个数据对象
2、调用这个数据对象的delete()方法实现删除

单个数据删除

批量删除

步骤
1、查找查询结果集中满足条件的全部QuerySet查询集合对象
2、调用查询集合对象的delete()方法实现删除

批量删除

伪删除

  • 通常不会轻易在业务里把数据真正删除掉,取而代之的是做伪删除,即在表中添加一个布尔型字段(is_active),默认是True;执行删除时,将欲删除数据的is_active字段置为False
  • 注意:用伪删除时,确保显示数据的地方,均加了is_active=True的过滤查询

F对象和Q对象

F对象

  • 一个F对象代表数据库中某条记录的字段的信息
  • 作用:
    -通常是对数据库中的字段值在不获取的情况下进行操作
    -用于类属性(字段)之间的比较
  • 语法

F对象

  • 示例1 更新Book实例中所有的零售价涨10元

示例1

  • 示例2 对数据库中两个字段的值进行比较,列出哪儿些书的零售价高于定价?

示例2

Q对象

当在获取查询结果集使用复杂的逻辑或 | 、逻辑非~等操作时可以借助于Q对象进行操作
如:想找出定价低于20元或清华大学出版社的全部书,可以写成

Q对象

Q对象在数据包django.db.models中。需要先导入在使用

作用:在条件中用来实现除and(&)以外的or(|)或not(~)操作
运算符:
& 与操作
| 或操作
~ 非操作
语法:

运算符

示例

示例


聚合查询和原生数据库操作

聚合查询

聚合查询是指对一个数据表中的一个字段的数据进行部分或全部进行统计查询。例如:查bookstore_book数据表中的全部书的平均价格,查询所有书的个总个数等,都要使用聚合查询。
聚合查询分为:

  • 整表聚合
  • 分组聚合

聚合查询-整表聚合

不带分组的聚合查询是指导将全部数据进行集中统计查询
聚合函数[需要导入]:
-导入方法:from django.db.models import *
-聚合函数:Sum,Avg,Count,Max,Min
语法:MyModel.objects.aggregate(结果变量名=聚合函数('列'))
-返回结果:结果变量名和值组成的字典
格式为:{"结果变量名":值}

聚合查询-分组聚合

分组聚合是指通过计算查询结果中每一个对象所联动的对象集合,从而得出总计值(也可以是平均值或总和),即为查询集的每一项生成聚合。
语法:
-QuerySet.annotate(结果变量名=聚合函数('列'))
返回值:
-QuerySet
1、通过先用查询结果MyModel.objects.values查找查询要分组聚合的列
MyModel.objects.values('列1','列2')
如:

分组聚合

原生数据库操作

Django也可以支持直接调用sql语句的方式通信数据库
查询:使用MyModel.objects.raw()进行 数据库查询操作
语法:MyModel.objects.raw(sql语句,拼接参数)
返回值:RawQuerySet集合对象[只支持基础操作,比如循环]

原生数据库

原生数据库操作-SQL注入

使用原生语句时小心SQL注入
定义:用户通过数据上传,将恶意的SQL语句提交给服务器,从而达到攻击效果
案例一:用户在搜索好友的表单框里输入 '1 or 1=1'

sql注入

攻击结果:可查询出所有用户数据
sql注入防范

sql注入防范

原生数据库操作 - cursor

完全跨过模型类操作数据库 - 查询/更新/删除
1、导入cursor所在的包
from django.db import connection
2、用创建cursor类的构造函数创建cursor对象,在使用cusor对象,为保证在出现异常时能释放cursor资源,通常使用with语句进行创建操作

cursor操作

示例

demo


admin后台管理-1

什么是admin管理后台

  • django提供了比较完善的后台管理数据库的接口,可供开发过程中调试和测试使用
  • django会搜集所有已注册的模型类,为这些模型类提供数据管理界面,供开发者使用

demo

demo

admin配置步骤

  • 创建后台管理账号 - 该账号为管理后台最高权限账号
    python manage.py createsuperuser

demo

admin后台管理-2

注册自定义模型类

若要自己定义的模型类也能在/admin后台管理界中显示和管理,需要将自己的类注册到后台管理界面
注册步骤:
1、在应用app中的admin.py中导入注册要管理的模型models类,如:from .models import Book
2、调用admin.site.register方法进行注册,如:admin.site.register(自定义模型类)

修改自定义模型类的数据模式

  • 在admin后台管理数据库中对自定义的数据记录都展示为'XXXXobject'类型的记录,不便于阅读和判断
  • 在用户自定义的模型类中可以重写def__str__(self):方法解决显示问题,如:

demo

模型管理器类

作用:
为后台管理界面添加便于操作的新功能
说明:
后台管理器类须继承自django.contrib.admin里的ModelAdmin
使用方法
1、在<应用app>/admin.py里定义模型管理器类

demo

2、绑定注册模型管理器和模型类

demo

案例:

demo

1、list_display去控制哪些字段会显示在Admin的修改列表页面中
2、list_display_links可以控制list_display中的字段是否应该链接到对象的“更改”页面
3、list_filter设置激活Admin修改列表页面右侧栏中的过滤器
4、search_fields设置启用Admin更改列表页面上的搜索框
5、list_editable设置为模型上的字段名称列表,这将允许在更改列表页面上进行编辑
官方文档

再谈Meta类

通过Meta内嵌类定义模型类的属性,用法如下:

Meta类


关系映射-1

什么是关系映射

  • 在关系型数据库中,通常不会把所有数据都放在同一张表中,不易于扩展,常见关系映射有:
    1、一对一映射
    如:一个身份证对应一个人
    2、一对多映射
    如:一个班级可以有多个学生
    3、多对多映射
    如:一个学生可以报多个课程,一个课程可以有多个学生学习

一对一【创建】

  • 一对一是表示现实事物间存在的一对一的对应关系。
  • 如:一个家庭只有一个户主,一个男人有一个妻子,一个人有一个唯一的指纹信息等。
  • 语法:OneToOneField(类名,on_delete=XXX)

demo

  • 特殊字段选项【必须】
  • on_delete - 级联删除
    1、models.CASCADE级联删除。Django模拟SQL约束ON DELETE CASCADE的行为,并删除包含ForeignKey的对象。
    2、models.PROTECT抛出ProtectedError以阻止被引用对象的删除;[等同于mysql默认的RESTRICT]
    3、SET_NULL设置ForeignKey null;需要指定null = True
    4、SET_DEFAULTForeignKey设置为其默认值;必须设置ForeignKey的默认值
    官方文档
  • 示例 - 创建模型类 - oto/models.py

model

一对一【创建数据】

  • 无外键的模型类[Author]:
    author1 = Author.objects.create(name='XXX')
  • 有外键的模型类[Wife]
wife1 = Wife.objects.create(name='YYY',author=author1)
# 关联XXXobj
wife1 = Wife.objects.create(name='YYY',author_id=1)
# 关联王老师对应主键值

一对一【查询数据】

1、正向查询:直接通关外键属性查询,则称为正向查询

demo

2、反向查询 - 没有外键属性的一方,可以调用反向属性查询到关联的另一方

demo


关系映射-2

一对多 - 定义

一对多是表现现实事物间存在的一对多的对应关系
如:一个学校有多个班级,一个班级有多个学生,一本图书只能属于一个出版社,一个出版社允许出版多本图书
一对多需要明确出具体角色,在多表上设置外键

一对多 - 创建

语法
当一个A类对象可以关联多个B类对象时

demo

ForeignKey必须指定on_delete模式
示例 - 创建模型类 - otm/models.py

demo

一对多 - 创建数据

先创建"一"在创建"多"

demo

一对多 - 查询数据

1、正向查询[通过Book查询Publisher]

demo

2、反向查询[通过Publisher查询对应的所有的Book]
需要用到反向属性

demo

多对多 - 定义

多对多表达对象之间多对多复杂关系,如:每个人都有不同的学校(小学,初中,高中,......),每个学校都有不同的学生......

  • mysql中创建多对多需要依赖第三张表来实现
  • Django中无需手动创建第三张表,Djnago自动完成
    语法:在关联的两个类中的任意一个类中,增加:
  • 属性 = models.ManyToManyField(MyModel)
    用法示例:
    一个作者可以出版多本图书
    一本图书可以被多名作者同时编写

demo

多对多 - 创建数据

demo

多对多 - 查询数据

1、正向查询 有多对多属性的对象 查 另一方

demo

2、反向查询

demo


cookies和session-1

会话定义

  • 从打开浏览器访问一个网站,到关闭浏览器结束此次访问,称之为一次会话
  • HTTP协议是无状态的,导致会话状态难以保持
  • 试想一下,如果不保持会话状态,在电商网站购物的场景体验?
  • Cookies和Session就是为了保持会话状态而诞生的两个存储技术

Cookies-定义

cookies是保存在客户端浏览器上的存储空间
Chrome浏览器可能通过开发者工具的Application >> Storage >> 'Cookies'查看和操作浏览器端所有的Cookies值
火狐浏览器可能通过开发者工具的存储 -> Cookies 查看

Cookies特点

  • cookies在浏览器上是以键-值对的形式进行存储的,键和值都是以ASCII字符串的形式存储(不能是中文字符串)
  • 存储的数据带有生命周期
  • cookies中的数据是按域存储隔离的,不同的域之间无法访问
  • cookies的内部的数据会在每次访问此网址时都会携带到服务器端,如果cookies过大会降低响应速度。

Cookies的使用 - 存储

HttpResponse.set_cookie(key,value='',max_age=None,expires=None)
-key:cookie的名字
-value:cookie的值
-max_age:cookie存活时间,秒为单位
-expires:具体过期时间
-当不指定max_age和expires时关闭浏览器时此数据失效

Cookies的使用 - 存储(续)
存储示例:

  • 添加cookie

demo

  • 修改cookie

demo

Cookies的使用 - 删除&获取
删除Cookies
-HttpResponse.delete_cookie(key)
-删除指定的key的Cookie。如果key不存在则什么也不发生
获取Cookies
-通过request.COOKIES绑定的字典(dict)获取客户端的COOKIES数据。value = request.COOKIES.get('cookies名','默认值')

  • 删除cookie

demo

  • 获取cookie

demo


cookies和session-2

session定义

session是在服务器上开辟一段空间用于保留浏览器和服务器交互时的重要数据
实现方式
-使用session需要在浏览器客户端启动cookie,且在cookie中存储sessionid。
-每个客户端都可以在服务器端有一个独立的session
-注意:不同的请求者之间不会共享这个数据,与请求者一一对应

session初始配置

settings.py中配置session
1、向INSTALLED_APPS列表中添加:

demo

2、向MIDDLEWARE列表中添加:

demo

session的使用

Django中session是一个类似于字典的SessionStore类型的对象,可以用类拟于字典的方式进行操作。session能够存储如字符串,整型,字典,列表等。
1、保存session的值到服务器
request.session['KEY'] = VALUE
2、获取session的值
value = request.session['KEY']
value = request.session('KEY',默认值)
3、删除session
del request.session['KEY']

settings.py中相关配置项
1、SESSION_COOKIE_AGE
作用:指定sessionid在cookies中的保存时长(默认是2周),如下:
例如:SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2
2、SESSION_EXPIRE_AT_BROWSER_CLOSE = True
设置只要浏览器关闭时,session就失效(默认为False)
注意:Django中的session数据存储在数据库中,所以使用session前需要确保已经执行过migrate

Django session的问题

1、django_session表是单表设计;且该表数据量持续增持【浏览器故意删掉sessionid & 过期数据未删除】
2、可以每晚执行python manage.py clearsessions【该命令可删除已过期的session数据】

Cookies vs Session

demo


缓存-1

Django官方文档

缓存的定义

  • 定义:缓存是一类可以更快的读取数据的介质统称,也指其他可以加快数据读取的存储方式。一般用来存储临时数据,常用的介质是读取速度很快的内存。
  • 意义:视图渲染有一定成本,数据库的频繁查询过高;所以对于低频变动的页面可以考虑使用缓存技术,减少实际渲染次数;用户拿到响应的时间成本会更低。
  • 案例分析

demo

优化思想-转自官网

demo

缓存场景

1、博客列表页
2、电商商品详情页

  • 场景特点:缓存的地方,数据变动频率较低

缓存配置

  • Django中设置缓存-数据库缓存
    将缓存的数据存储在您的数据库中
    说明:
    尽管存储介质没有更换,但是当把一次负责查询的结果直接存储到表里,比如多个条件的过滤查询结果,可避免重复进行复杂查询,提升效率;
    settings.py 中关于缓存的内容如下:

缓存

CACHES ={
    'default': {
        'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
        'LOCATION': 'my_cache_table', #缓存存储的表名
        'TIMEOUT': 60,  # default to 60 seconds formation 缓存保存的时间,单位秒,默认值300
        'OPTIONS':{
            'Max_ENTRIES': 300,   # 缓存最大数据条数
            'CULL_FREQUENCY': 5, # 缓存条数达到最大值,删除1/x的缓存数据
        }
    }

  • 数据缓存到服务器内存中
    配置样例

cache

  • 将缓存的数据存储到本地文件中
    配置样例

local

  • 使用自定义缓存
    尽管Django开箱即用地支持许多缓存后端,但有时可能希望使用自定义的缓存后端:要将外部缓存后端与Django一起使用。

实操流程

1、执行以下命令,创建出储存缓存的数据库表
python manage.py createcachetable
2、编辑settings.py配置文件,详细内容在缓存配置部分已详述

整体缓存策略

  • Django中使用缓存 - 视图函数中
    样例

views-cache

  • Django中使用缓存 - 路由中
    样例

path-cache


缓存-2

局部缓存策略

  • 缓存api的使用
    先引入cache对象
    方式1:使用caches['settings中CACHE中配置的key']导入具体对象
    例如:

cache

方式2:
from django.core.cache import cache相当于直接引入CACHES配置项中的'default'

调用api
1、cache.set(key,value,timeout) - 存储缓存
key:缓存的key,字符串类型
value:python对象
timeout:缓存储存时间(s),默认为CACHES中的TIMEOUT
返回值:None
2、cache.get(key) - 获取缓存
key:缓存的key
返回值:为key的具体值,如果没有数据,则返回None
3、cache.add(key,value) - 存储缓存,只在key不存在时生效
返回值:True[存储成功] False[存储失败]

例子:

example

4、cache.get_or_set(key,value,timeout) - 如果未获取到数据则执行set操作
返回值:value
5、cache.set_many(dict,timeout) - 批量缓存
dict:keyvalue的字典
timeout:存储时间(s)
返回值:插入不成功的key的数组
6、cache.get_many(key_list) - 批量获取缓存数据
key_list:包含key的数组
返回值:取到的key和value的字典
7、cache.delete(key) - 删除key的缓存数据
返回值:None
8、cache.delete_many(key_list) - 批量删除
返回值:None

浏览器缓存

  • 浏览器缓存策略

image

  • 强缓存
    不会向服务器发送请求,直接从缓存中读取资源
    1、响应头 - Expires
    定义:缓存过期时间,用来指定资源到期的时间,是服务器端的具体的时间点
    样例:Expires:Thu,02 Apr 2030 05:14:08 GMT
    2、响应头 - Cache-Control
    在HTTP/1.1中,Cache-Control主要用于控制网页缓存。比如当Cache-Control:max-age=120代表请求创建时间后的120秒,缓存失效
    说明:目前服务器都会带着这两个头同时响应给浏览器,浏览器优先使用Cache-Control

  • 协商缓存
    强缓存中的数据一旦过期,还需要跟服务器进行通信,从而获取最新数据;
    那么如果强缓存的数据是一些静态文件,大图片等?
    考虑到大图片这类比较费带宽且不易变化的数据,强缓存时间到期后,浏览器会去跟服务器协商,当前缓存是否可用,如果可用,服务器不必返回数据,浏览器继续使用原来缓存的数据,如果文件不可用,则返回最新数据。

1、Last-Modified响应头 和 If-Modified-Since请求头
说明:
(1)Last-Modified为文件的最近修改时间,浏览器第一次请求静态文件时,服务器如果返回Last-Modified响应头,则代表该资源为需协商的缓存
(2)、当缓存到期后,浏览器将获取到的Last-Modified值做为请求头If-Modified-Since的值,与服务器发请求协商,服务端返回304响应码[响应体为空],代表缓存继续使用,200响应码代表缓存不可用[响应体为最新资源]

2、ETag响应头和If-None-Match请求头
说明:
(1)ETag是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成),只要资源有变化,Etag就会重新生成;
(2)缓存到期后,浏览器将ETag响应头的值作为If-None-Match请求头的值,给服务器发请求协商;服务器接到请求头后,比对文件标识,不一致则认为资源不可用,返回200响应码[响应体为最新资源];可用则返回304响应码.


中间件

中间件的定义

  • 中间件是Django请求/响应处理的钩子框架。它是一个轻量级的、低级的插件系统,用于全局改变Django的输入或输出。
  • 中间件以类的形式体现
  • 每个中间件组件负责做一些特定的功能。例如,Django包含一个中间件组件AuthenticationMiddleware,它使用会话将用户与请求关联起来。

中间件示意

编写中间件

  • 中间件类需继承自django.utils.deprecation.MiddlewareMixin
  • 中间件类需实现下列五个方法中的一个或多个:
    • process_request(self,request)
      执行路由之前被调用,在每个请求上调用,返回NoneHttpResponse对象
    • process_view(self,request,callback,callback_args,callback_kwargs)
      调用视图之前被调用,在每个请求上调用,返回NoneHttpResponse对象
    • process_response(self,request,response)
      所有响应返回浏览器被调用,在每个请求上调用,返回HttpResponse对象
    • process_exception(self,request,exception)
      当处理过程中抛出异常时调用,返回一个HttpResponse对象
    • process_template_response(self,request,response)
      在视图函数执行完毕且视图返回的对象中包含render方法时被调用;该方法需要返回实现了render方法的响应对象

注:中间件中的大多数方法在返回None时表示忽略当前操作进入下一项事件,当返回HttpResponese对象时表示此请求结束,直接返回给客户端。

注册中间件

  • settings.py中需要注册一下自定义的中间件

注册中间件

  • 注意:配置为数组,中间件被调用时以‘先上到下’再‘由下到上’的顺序调用。

中间件执行总流程

中间件执行总流程

CSRF攻击

CSRF - 跨站伪造请求攻击
某些恶意网站上包含链接、表单按钮或者JavaScript,他们会利用登陆过的用户在浏览器中的认证信息试图在你的网站上完成某些操作,这就是跨站请求伪造(CSRF,Cross-Site Request Forgey)。

CSRF防范

  • django采用'对比暗号'机制防范攻击
  • Cookies中存储暗号1,模板中表单里藏着暗号2,用户只有在本网站下提交数据,暗号2才会随表单提交给服务器,django对比两个暗号,对比成功,则认为是合法请求,否则是违法请求-403响应码

CSRF防范配置步骤:

1、settings.py中确认MIDDLEWAREdjango.middleware.csrf.CsrfViewMiddleware是否打开
2、模板中,form标签下添加如下标签{% csrf_token %}

特别说明:
如果某个视图不需要django进行csrf保护,可以用装饰器关闭对此视图的检查
样例:

示例


分页

分页定义

  • 分页是指在web页面有大量数据需要显示,为了阅读方便在每个页面中只显示部分数据。
  • 优点:
    1、方便阅读
    2、减少数据提取量,减轻服务器压力
  • Django提供了Paginator类可以方便的实现分页功能
  • Paginator类位于django.core.paginator模块中

Paginator对象

负责分页数据整体的管理
对象的构造方法

paginator = Paginator(object_list,per_page)
  -参数
      - object_list 需要分类数据的对象列表
      - per_page 每页数据个数
  -返回值:
      - Paginator的对象
      - count:需要分页数据的对象总数
      - num_pages:分页后的页面总数
      - page_range:从1开始的range对象,用于记录当前页码数
      - per_page:每页数据的个数
paginator对象.page(number)
  - 参数 number为页码信息(从1开始)
  - 返回当前number页对应的页信息
  - 如果提供的页码不存在,抛出InInvalidPage异常
paginator异常exception:
InvalidPage:总的异常基类,包含以下两个异常子类
  - PageNotAnInteger:当向page()传入一个不是整数的值时抛出
  - EmptyPage:当向page()提供一个有效值,但是那个页面上没有任何对象时抛出

Page对象

page对象定义:负责具体某一页的数据的管理
创建对象
Paginator对象的page()方法返回Page对象
Page = paginator.page(页码)
Page对象属性

  • object_list:当前页上所有数据对象的列表
  • number:当前页的序号,从1开始
  • paginator:当前page对象相关的Paginator对象
  • has_next():如果有下一页返回True
  • has_previous():如果有上一页返回True
  • has_other_pages():如果有上一页或下一页返回True
  • next_page_number():返回下一页的页码,如果下一页不存在,抛出InvalidPage异常
  • previous_page_number():返回上一页的页码,如果上一页不存在,抛出InvalidPage异常。

django生成csv文件

csv文件定义

逗号分隔值(Comma-Separated Values,CSV,有时也称为字符分隔值,因为分割字符也可以不是逗号),其文件以纯文本形式存储表格数据(数字和文本)
说明:可以被常见制表工具,如excel等直接进行读取

python中生成csv文件

官方文档

#导入相关包
import csv

#写文件
with open('eggs.csv', 'w', newline='') as csvfile:
    spamwriter = csv.writer(csvfile, delimiter=' ',
                            quotechar='|', quoting=csv.QUOTE_MINIMAL)
    spamwriter.writerow(['Spam'] * 5 + ['Baked Beans'])
    spamwriter.writerow(['Spam', 'Lovely Spam', 'Wonderful Spam'])
#读文件
with open('eggs.csv', newline='') as csvfile:
    spamreader = csv.reader(csvfile, delimiter=' ', quotechar='|')
    for row in spamreader:
        print(', '.join(row))

CSV文件下载

在网站中,实现下载CSV,注意如下:

  • 响应Content-Type类型需修改为text/csv。这告诉浏览器该文档是CSV文件,而不是HTML文件。
  • 响应会获得一个额外的Content-Disposition标头,其中包含CSV文件的名称。它将被浏览器用于开启“另存为”对话框
import csv
from django.http import HttpResponse
from .models import Book

def make_csv_view(request):
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="mybook.csv"'
    writer = csv.writer(response)
    #以下就是正常的csv文件写入
    #写入示例:
    writer.writerow(['id', 'title'])
    all_book = Book.objects.all()
    for b in all_book:
        writer.writerow([b.id, b.title])
    
    #完成写入,返回response
    return  response

内建用户系统

定义

  • Django带有一个用户认证系统。它处理用户账号、组、权限以及基于cookie的用户会话。
  • 用户可以直接使用Django自带的用户表

官方文档

基本字段

模型类位置from django.contrib.auth.models import User

基本字段

基本字段

基本模型操作-创建用户

1、创建普通用户create_user

from django.http import HttpResponse
from django.contrib.auth.models import User

def cre_user(request):
    user = User.objects.create_user(username='用户名',password='密码',email='邮箱',...)

2、创建超级用户create_superuser

from django.http import HttpResponse
from django.contrib.auth.models import User

def cre_supuser(request):
    user = User.objects.create_superuser(username='用户名',password='密码',email='邮箱',...)

基本模型操作-删除用户

from django.http import HttpResponse
from django.contrib.auth.models import User

def del_user(request):
    try:
        user = User.objects.get(username='用户名')
        user.is_active = False #标记当前用户冻结
        user.save()
        print("删除普通用户成功")
    except:
        print("删除普通用户失败")

基本模型操作-校验密码

from django.http import HttpResponse
from django.contrib.auth.models import User

def auth(request):
    user = authenticate(username='username',password='password')

说明:如果用户名密码校验成功则返回对应的user对象,否则返回None

基本模型操作-修改密码

from django.http import HttpResponse
from django.contrib.auth.models import User

def changepw(request):
    try:
        user = User.objects.get(username='usrname')
        user.set_password('mima')
        user.save()
        return HttpResponse("修改密码成功")
    except:
        return HttpResponse("修改密码失败")

基本模型操作-登陆状态保持

from django.contrib.auth import login
from django.http import HttpResponse
from django.contrib.auth.models import User

def login_view(request):
    user =User.authenticate(username="username",password="password")
    login(request, user)

基本模型操作-登陆状态校验

from django.contrib.auth import login
from django.http import HttpResponse
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required

@login_required
#此装饰器那个函数需要校验登陆状态就放到那个函数上面
def index_view(request):
    #该视图函数必须为用户登陆状态下才可访问
    #当前登录用户可通过request.user获取
    login_user = request.user

基本模型操作-登陆状态取消

from django.contrib.auth import login
from django.http import HttpResponse
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from django.contrib.auth import logout

def logout_view(request):
    logout(request)

内建用户表-扩展字段

方法1:通过建立新表,跟内建表做1对1
方法2:继承内建的抽象user模型类

内建用户表-继承内建抽象类

1、添加新的应用
2、定义模型类 继承AbstractUser
3、settings.py中指明AUTH_USER_MODEL = "应用名.类名"
注意:此操作要在第一次Migrate之前进行

示例
添加user应用
user/models.py

from django.db import models
from django.contrib.auth.models import AbstractUser

#create your models here
class userInfo(AbstractUser):
    phone = models.CharField(max_length=11,default='')

settings.py添加配置
AUTH_USER_MODEL = 'user.UserInfo'

user/view.py

from user.models import UserInfo

def add_user(request):
    UserInfo.objects.create_user(username='username',password='',phone='12345678901')

文件上传

定义&场景

  • 定义:用户可以通过浏览器将图片等文件传至网站
  • 场景:
    • 用户上传头像
    • 上传流程性的文档[pdf,txt等]

上传规范 - 前端[HTML]

文件上传必须为POST提交方式
表单<form>中文件上传时必须带有enctype = "multipart/form-data"时才会包含文件内容数据。
表单中用<input type = "file" name="xxx">标签上传文件

上传规范 - 后端[Django]

视图函数中,用request.FILES取文件框的内容
file = request.FILES['XXX']
说明:
1、FILES的key对应页面中file框的name值
2、file绑定文件流对象
3、file.name文件名
4、file.file文件的字节流数据
配置文件的访问路径和存储路径
settings.py中设置MEDIA相关配置;Django把用户上传的文件,统称为media资源
Django把用户上传的文件,统称为media资源

#file:settings.py
MEDIA_URL = 'http://localhost/media'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

MEDIA_URLMEDIA_ROOT需要手动绑定
步骤:主路由中添加路由

from django.conf import settings
from django.conf.urls.static import static

urlpatterns += static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)

说明:等价于做了MEDIA_URL开头的路由,Django接到该特征请求后去MEDIA_ROOT路径查找资源

文件写入方案1:传统的open方式

@csrf_protect
def upload_view(request):
    if request.method == 'GET':
        return render(request, 'test_upload.html')
    elif request.method == 'POST':
        a_file = request.FILES['myfile']
        print("上传文件名是:",a_file.name)
        filename = os.path.join(settings.MEDIA_ROOT, a_file.name)
        with open(filename,'wb') as f:
            data = a_file.file.read()
            f.write(data)
        return HttpResponse("接收文件:" + a_file.name + "成功")

文件写入方案2:借助ORM
字段:FileField(upload = '子目录名')

@csrf_exempt
def upload_view_orm(request):
    if request.method == "GET":
        return render(request,"test_upload.html")
    elif request.method == "POST":
        title = request.POST['title']
        a_file = request.FILES['myfile']
        Content.objects.create(desc=title, myfile=a_file)
        return HttpResponse("----upload is ok----")

django发送邮件

业务场景

  • 业务告警
  • 邮件验证
  • 密码找回

邮件相关协议-SMTP

  • SMTP的全称是"Simple Mail Transfer Protocol",即简单邮件传输协议(25号端口)。
  • 它是一组用于从源地址到目的地址传输邮件的规范,通过它来控制邮件的中转
  • 属于“推送”协议

邮件相关协议-IMAP

  • IMAP全称是Internet Mail Access Protocol,即交互式邮件访问协议,是一个应用层协议(端口是143)。
  • 用来从本地邮件客户端访问远程服务器上的邮件。
  • 属于“拉取”协议

邮件相关协议-POP3

  • POP3是Post Protocol 3的简称,即邮局协议的第3个版本,是TCP/IP协议族中的一员(默认端口是110)。
  • 本协议主要用于支持使用客户端远程管理在服务器上的电子邮件
  • 属于“拉取”协议

IMAP VS POP3

两者均为“拉取”型协议,负责从邮件服务器中下载邮件

  • IMAP具备摘要浏览功能,可预览部分摘要,再下载整个邮件
  • IMAP为双向协议,客户端操作可反馈给服务器

  • POP3必须下载全部邮件,无摘要功能
  • POP3为单向协议,客户端操作无法同步服务器

原理图

Django发邮件

  • Django中配置邮件功能,主要为SMTP协议,负责发邮件
  • 原理:
    • 给Django授权一个邮箱
    • Django用该邮箱给对应收件人发送邮件
    • django.core.mail 封装了电子邮件的自动发送SMTP协议

Django配置

/settings.py

#邮件相关配置
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com' #谷歌邮箱SMTP服务器地址
EMAIL_PORT = 25 # SMTP服务的端口号
EMAIL_HOST_USER = "xxxx@gmail.com" #发送邮件的邮箱账号
EMAIL_HOST_PASSWORD = "**********" #对应的邮箱密钥,不是密码,是POP3或IMAP对应的密钥
EMAIL_USE_TLS = False #与SMTP服务器通信时,是否启动TLS链接(安全链接)默认False

函数调用

view.py/

from django.core import mail
def mail_send(request):
    mail.send_mail(
        subject="",#题目
        message="",#消息内容
        from_email="",#发送者【当前配置邮箱】
        recipient_list=[""]#接收者邮件列表
    )

项目部署-uwsgi

基础概念

项目部署是指在软件开发完毕后,将开发机器上运行的软件实际安装到服务器上进行长期运行
1、在安装机器上安装和配置同版本的环境【py,数据库等】
2、django项目迁移

  • 将项目传输到服务器
    3、用uWSGI替代python manage.py runserver方法启动服务器
    4、配置nginx反向代理服务器
    5、用nginx配置静态文件路径,解决静态路径问题

WSGI定义

WSGI(Web Server Gateway Interface)Web服务器网关接口,是Python应用程序或框架和Web服务器之间的一种接口,被广泛使用。
python manage.py runserver通常只在开发和测试环境中使用。当开发结束后,完善的项目代码需要在一个高效稳定的环境中运行,这时就需要使用WSGI。

img

uWSGI定义

uWSGI是WSGI的一种,它实现了http协议、WSGI协议以及uWSGI协议等协议,常在不是DjangoFlask开发的PythonWeb项目时使用,作为连接Nginx与应用程序之间的桥梁。
uWSGI功能完善,支持协议众多,在python web圈热度极高。

img

WSGI与uWSGI协议区别

  • uWSGI是Python Web服务器,实现了WSGI通信规范和uwsgi协议;
  • WSGI全名Web Server Gateway Interface,是一个Web服务器(如uWSGI服务器)与web应用(如用Django或Flask框架写的程序)通信的一种规范;
  • uwsgi是WSGI通信规范中的一种自有协议。

uWSGI安装

  • 通过pip命令
    pip install uwsgi
    ps:建议使用国内pip源
  • 下载安装脚本
    curl http://uwsgi.it/install | bash -s default /tmp/uwsgi
    将 uWSGI 二进制安装到 /tmp/uwsgi ,你可以修改它。
  • 源码安装
wget http://projects.unbit.it/downloads/uwsgi-latest.tar.gz
tar zxvf uwsgi-latest.tar.gz
cd uwsgi-latest
make
  • 验证安装

sudo pip freeze | grep -i 'uwsgi'
如果成功则会输出uwsgi的版本信息
ps:此方法只适用于linux下使用pip安装的情况
2)
可编写测试文件测试,主要内容如下:

def application(env, start_response):
    start_response('200 OK', [('Content-Type','text/html')])
    return [b"Hello World"]

配置uWSGI

添加配置文件项目文件夹/项目同名文件夹/uwsgi.ini
例如:

[uwsgi]
http=127.0.0.1:8000
chdir=/home/......
wsgi-file=/......
process = 4
threads= 2
pidfile=uwsgi.pid
daemonize=uwsgi.log
master=True

文件以[uwsgi]开头,内容如下:
socket = 127.0.0.1:8000
套接字方式的 IP地址:端口号【此模式需要有nginx】
http=127.0.0.1:8000
Http通信方式的 IP地址:端口号
chdir=项目路径
项目当前工作目录
wsgi-file=my_project/wsgi.py
节目中wsgi.py文件的目录,相对于当前工作目录
process=4
进程个数
threads=2
每个进程的线程个数
pidfile=uwsgi.pid
服务的pid记录文件
daemonize=uwsgi.log
服务的日志文件位置
master=true
开启主进程管理模式

特殊说明:Djangosettings.py需要做如下配置
1、修改settings.pyDEBUG=True改为DEBUG=False
2、修改settings.pyALLOWED_HOSTS= []改为ALLOWED_HOSTS = ['网站域名或者服务监听的ip地址']

uWSGI的运行管理

  • 启动uwsgi
    在uWSGI配置文件所在的目录
    uwsgi --ini uwsgi.ini
  • 停止uwsgi
    在uWSGI配置文件所在的目录
    uwsgi --stop uwsgi.pid

uWSGI的运行说明

1、无论是启动还是关闭,都需要执行ps aux | grep 'uwsgi'确认是否符合预期
2、启动成功后,进程在后台执行,所有日志均输出在配置文件所在目录的uwsgi.log
3、Django中代码有任何修改,都需要重新把启动uwsgi

uWSGI测试

在浏览器地址栏输入http://127.0.0.1:8000/url进行测试。
ps:此时端口8000被uWSGI进程监听,并非runserver
如果当前有预期返回,则uWSGI启动成功

uWSGI常见问题汇总

1、启动失败:端口被占用
原因:有其他进程占用uWSGI启动的端口;
解决方案:可执行sudo lsof -i:端口号查询出具体进程;杀掉进程后,重启uWSGI即可。
2、停止失败:stop无法关闭uWSGI
原因:重复启动uWSGI,导致pid文件中的进程号失准
解决方案:ps出uWSGI进程,手动杀掉(命令:kill)


项目部署-Nginx

什么是Nginx?

  • Nginx (engine x) 是一个高性能的 HTTP 和反向代理 Web 服务器,同时也提供了 IMAP/POP3/SMTP 服务。Nginx 是由俄国的程序设计师伊戈尔·赛索耶夫用 C语言开发的。Nginx 作为一款轻量级的Web 服务器、反向代理服务器及电子邮件代理服务器,它以自身的稳定性、并发能力强和超低的系统资源消耗而闻名。Nginx 的主要作用是作为 Web 服务器的反向代理服务器,实现 Web 服务器的负载均衡以及站点资源的动静分离 ,我们所熟知的百度、京东、腾讯、淘宝等都使用了 Nginx。
  • C语言编写,执行效率高
  • nginx作用
    - 负载均衡,多台服务器轮流处理请求
    - 反向代理
  • 原理:
    - 客户端请求nginx,再由nginx将请求转发uWSGI运行的django

img

  1. 反向代理服务器
    反向代理服务器位于客户端用户与目标服务器之间,但是对于用户而言,反向代理服务器就相当于目标服务器,即用户直接访问反向代理服务器就可以获得目标服务器的资源。同时,用户不需要知道目标服务器的地址,也无须在用户端作任何设定。反向代理服务器通常可用来作为 Web 加速,用来提升用户访问站点的速度,所以使用 Nignx 作为 Web 服务器的前置服务器可以降低网络和服务器的负载,从而提高访问效率。
  2. 什么是负载均衡
    负载均衡(Load Balance),它的意思就是将工作任务分摊到多个操作单元上进行执行,比如 Web 服务器、FTP 服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。单个服务器解决不了,我们增加服务器的数量,然后将请求分发到各个服务器上面,将原先请求到单个服务器上面的情况改为将请求分发到多个服务器上,将负载分发到不同的服务器,这就是负载均衡。
  3. 理解动静分离
    所谓动静分离就是为了加快网站的解析速度,可以把动态页面和静态页面由不同的服务器来解析,加快解析速度,降低单个服务器的压力。进而提升整个服务访问性能和可维护性。
  4. Nginx应用场景
    主要有以下三大场景,一、作为虚拟主机,它可以实现在一台服务器虚拟出多个网站;二、用来充当 HTTP 服务器。Nginx 是一个 HTTP 服务器可以独立提供 HTTP 服务,也可以做网页静态服务器;三、实现反向代理、负载均衡。当网站的访问量达到一定程度后,单台服务器不能满足用户的请求,这时就需要用多台服务器组成服务集群并把 Nginx 做为反向代理服务器,实现多台服务器可以平均分担负载的目的,这样就不会造成某台服务器负载过高而宕机,而集群中另一台服务器闲置的情况。

安装

安装Nginx

Nginx官方文档

img

img

  • 安装先决条件:
    sudo apt install curl gnupg2 ca-certificates lsb-release ubuntu-keyring

  • 导入官方 nginx 签名密钥,以便 apt 可以验证包的真实性。获取密钥:

curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
    | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
  • 验证下载的文件是否包含正确的密钥:
gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg
  • 输出应包含完整的指纹 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 ,如下所示:
pub   rsa2048 2011-08-19 [SC] [expires: 2024-06-14]
      573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62
uid                      nginx signing key <signing-key@nginx.com>

如果指纹不同,请删除该文件。

  • 要为稳定的 nginx 包设置 apt 存储库,请运行以下命令:
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" \
    | sudo tee /etc/apt/sources.list.d/nginx.list
  • 如果您想使用主线 nginx 包,请运行以下命令:
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/mainline/ubuntu `lsb_release -cs` nginx" \
    | sudo tee /etc/apt/sources.list.d/nginx.list
  • 设置存储库固定以更喜欢我们的包而不是分发提供的包:
echo -e "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" \
    | sudo tee /etc/apt/preferences.d/99nginx
  • 要安装 nginx,请运行以下命令:
sudo apt update
sudo apt install nginx
  • 验证安装
    nginx -v
    如果输出版本信息则安装成功

配置

uwsgi 配置

uwsgi支持ini、xml等多种配置方式,本文以 ini 为例, 在/etc/目录下新建uwsgi9090.ini(当然你也可以建在项目目录下,下面初始化的时候注意路径变化),添加如下配置:

[uwsgi]
socket = 127.0.0.1:9090
master = true         //主进程
vhost = true          //多站模式
no-site = true        //多站模式时不设置入口模块和文件
workers = 2           //子进程数
reload-mercy = 10     
vacuum = true         //退出、重启时清理文件
max-requests = 1000   
limit-as = 512
buffer-size = 30000
pidfile = /var/run/uwsgi9090.pid    //pid文件,用于下面的脚本启动、停止该进程
daemonize = /website/uwsgi9090.log

Nginx 配置

找到nginx的安装目录(如:/usr/local/nginx/),打开conf/nginx.conf文件,修改server配置:

server {
        listen       80;
        server_name  localhost;
        
        location / {            
            include  uwsgi_params;
            uwsgi_pass  127.0.0.1:9090;              //必须和uwsgi中的设置一致
            uwsgi_param UWSGI_SCRIPT demosite.wsgi;  //入口文件,即wsgi.py相对于项目根目录的位置,“.”相当于一层目录
            uwsgi_param UWSGI_CHDIR /demosite;       //项目根目录
            index  index.html index.htm;
            client_max_body_size 35m;
        }
    }

设置完成后,在终端运行:

uwsgi --ini /etc/uwsgi9090.ini &
/usr/local/nginx/sbin/nginx

在浏览器输入:http://127.0.0.1,你就可以看到 django 的 "It work" 了。

排错

  • 排查依据:日志
    Nginx日志位置:
    异常信息:/var/log/nginx/error.log
    正常访问信息:/var/log/nginx/access.log
    uwsgi日志位置:
    项目同名目录下,uwsgi.log
  • Web访问错误码
    1、502
    代表nginx反向代理配置成功,但是对应的uwsgi未启动
    2、404响应
    1)路由的确不在django配置中
    2)nginx配置错误,未禁止掉try_files

静态文件配置

1、创建新的路径,主要存放Django所有静态文件,如:/home/tarena/项目名_static/
2、在Django settings.py中添加新配置
img
3、进入项目,执行python manage.py collectstatic,然后Django将项目中所有静态文件复制到STATIC_ROOT中,包括Django内建的静态文件
4、Nginx配置中添加新配置
server {
......
location / {
.......
# root 第一步中创建的绝对路径
root /home/tarena/项目名_static/; # (第一步中创建的路径)
}
}

自定义404/500报错页

在模板文件夹内添加404.html/500.html模板,当视图触发对应的异常时将会被显示。
404.html/500.html仅在发布版中(settings.py中的DEBUG = False )才起作用,当响应处理函数触发对应异常时就会跳转到对应界面。

邮箱警告

当正式服务器上代码运行有报错时,可将错误追溯信息发至指定的邮箱
settings.py中-在基础邮箱授权后添加如下配置:

#关闭调试模式
DEBUG = False
#错误报告接收方
ADMINS = [('xiaohan','xxxx@example.com'),('wxxx','xxx@example.com')]
#发送错误报告方,默认为root@localhost账户,多数邮件服务器会拒绝
SERVER_EMAIL = 'email配置中的邮箱'

报错邮件中会显示一些错误的追踪,这些错误追踪中会出现如password等敏感信息,Django已经将配置文件中的敏感信息过滤修改为多个星号,但是用户自定义的视图函数需要用户手动过滤敏感信息
可过滤如下信息:
局部变量
POST提交数据

过滤敏感信息 - 局部变量

例如:

from django.views.decorators.debug import sensitive_variables

@sensitive_variables('user','pw','cc')
def process_info(user):
  pw = user.pass_word
  cc = user.credit_card_number
  name = user.name

1、若报错邮件中牵扯到user、pw、cc等局部变量的值,则会将其替换成**********,而name变量还显示其真实值
2、多个装饰器时,需要将其放在最顶部
3、若不传参数,则过滤所有局部变量的值

过滤敏感信息 - POST数据

from django.views.decorators.debug import sensitive_variables

@sensitive_variables('password','username')
def index(request):
    s = request.POST['username'] + request.POST['abcd']
    #'abcd'并不存在,此时引发error
    #POST中username及password的值会被替换成 *********

未完待续......

posted @ 2022-09-05 16:51  VictoryHan  阅读(98)  评论(0编辑  收藏  举报