Django总结

文章目录


这篇文章是复习Django学习了那些内容,做一个总结,查缺补漏

一、Web应用

web应用程序是一种可以通过web访问的应用程序,用户只需有浏览器即可,不需要再安装其他软件
比如:淘宝网、京东网、博客园等都是基于web应用的程序

Web应用程序的优点

  1. 只需要一个适用的浏览器
  2. 节省硬盘空间
  3. 不需要更新,所有的新特新都在服务器上执行,从而自动传达到客户端
  4. 可以跨平台使用:Windows, Mac, Linux 等

Web应用程序的缺点

严重依赖服务端正常运行,一旦服务端出现问题,客户端就会收到影响

应用程序有两种模式C/S、B/S

C/S是客户端/服务端程序,也就是说这类程序一般独立运行。
而B/S就是浏览器端/服务端应用程序,这类应用程序一般借助IE等浏览器来运行。web应用程序一般是B/S模式。

在MySQL的情境下,客户端和服务器可以存在于同一台计算机上,也可以分布在不同的计算机上,通过网络进行通信。这种C/S架构提供了更好的灵活性和可伸缩性,使得多个客户端可以同时连接到同一个数据库服务器,实现数据的共享和集中管理。

总体而言,MySQL作为关系型数据库管理系统,通过C/S架构提供了一种有效的方式来处理数据库操作,使得应用程序和数据库之间的交互更为灵活和高效。

C/S 客户端/服务端

我们之前学习的MySQL也是C/S架构,将客户端和服务端装在同一台机器上。

现在可以尝试连接另外一台计算机的MySQL操作如下:

局域网连接其他电脑的MySQL数据库

1.先用其他电脑再cmd命令行ping本机ip

查询本机ip,在命令行输入ipconfig
在这里插入图片描述

若是ping不通的话就需要关闭防火墙,打开控制面板-----防火墙----关闭所有防火墙
在这里插入图片描述

2.开放MySQL的访问

打开MySQL 命令行链接mysql:mysql -hlocalhost -uroot -p
输入密码:Enter password: ******(自己的密码)
打开 mysql 数据库:use mysql(因为MySQL的权限存在这个里面)
将user=‘root’的用户访问权限为all:update user set host=’%’ where user=‘root’;(把host改为%,相当于任何用户都可以连接。)
让赋予的权限立即生效:flush privileges;

C:\Users\ut>mysql -hlocalhost -uroot -p
Enter password: ******
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 11
Server version: 8.0.15 MySQL Community Server - GPL

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use mysql
Database changed

mysql> update user set host='%' where host= 'localhost';
Query OK, 4 rows affected (0.01 sec)
Rows matched: 4  Changed: 4  Warnings: 0

mysql> flush   privileges ;
Query OK, 0 rows affected (0.01 sec)

不出意外的话重启一下自己的mysql服务,同事电脑就能连上自己的库了,如果不行试下下面的命令

GRANT ALL PRIVILEGES ON *.* TO root @'%' IDENTIFIED BY "mypassword";
FLUSH PRIVILEGES; 

% 表示所有的IP都能访问,也可以修改为专属的
mypassword 为连接密码 需要修改为你自己的

B/S 浏览器/服务端

我们在用的Django框架就是B/S架构

如何让同局域网别的电脑访问你写的网页:
首先搭建好你的网页,自己访问无问题,同上关闭你的防火墙。
在这里插入图片描述

1.将ip地址改成0.0.0.0,所有用户都可以访问

2.将setting.py下的ALLOWED_HOSTS=[‘*’]接受所有的

在这里插入图片描述

做完以上操作就可以让别人访问你的页面
在这里插入图片描述
输入IP地址加上端口号,再加上需要访问的页面

基于socket编写一个Web应用

手写服务端,让浏览器访问

import socket, time
def run():
    server = socket.socket()
    server.bind(('127.0.0.1', 8000))
    server.listen(3)

    while True:
        sock, addr = server.accept()
        server_data = sock.recv(1024)
        now = time.strftime('%Y-%m-%d %X', time.localtime())
        with open('index.html', 'r', encoding='utf-8') as f:
            data = f.read()
        data = data.replace('sb', now)
        sock.send(('HTTP/1.1 200 ok \r\n\r\n%s' % data).encode('utf-8'))


if __name__ == '__main__':
    run()

二、Http协议

1.http协议是什么

http协议是超文本传输协议,服务器与本地浏览器之间传输超文本的传送协议

2.http协议特性

1. 基于TCP/IP协议之上的应用层协议

它是可靠传输,不会丢失数据

2. 基于请求-响应模式

HTTP协议规定,请求从客户端发出,最后服务器端响应该请求并 返回。
换句话说,肯定是先从客户端开始建立通信的,服务器端在没有 接收到请求之前不会发送响应
在这里插入图片描述

3. 无状态保存

HTTP是一种不保存状态,即无状态(stateless)协议。HTTP协议 自身不对请求和响应之间的通信状态进行保存。也就是说在HTTP这个 级别,协议对于发送过的请求或响应都不做持久化处理。
在这里插入图片描述

4.无连接

就是每次连接处理一个请求,服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。

3.Http请求协议与响应协议

请求协议:

请求首行:
请求方式
请求地址
请求协议版本号

请求头:有K/V键值对组成 \r\n

请求体:get请求没有请求体,post请求有请求体
在这里插入图片描述
get请求

'''
------请求首行------
b'GET / HTTP/1.1\r\n

------请求头-----
Host: 127.0.0.1:8000\r\n
Connection: keep-alive\r\n
Cache-Control: max-age=0\r\n
sec-ch-ua: "Microsoft Edge";v="119", "Chromium";v="119", "Not?A_Brand";v="24"\r\n
sec-ch-ua-mobile: ?0\r\n
sec-ch-ua-platform: "Windows"\r\n
Upgrade-Insecure-Requests: 1\r\n
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\n
Sec-Fetch-Site: none\r\n
Sec-Fetch-Mode: navigate\r\n
Sec-Fetch-User: ?1\r\n
Sec-Fetch-Dest: document\r\n
Accept-Encoding: gzip, deflate, br\r\n
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6\r\n
Cookie: o2State={%22webp%22:true%2C%22avif%22:false};csrftoken=X7rlh2l36LXbjh0COtpHqlaJOZFxjDzhbx8XPh0k9Ncl9in9VCemv4OIfyjFo1T4\r\n\r\n'

------请求体-----


'''

post请求

'''
------请求首行------
b'POST / HTTP/1.1\r\n


------请求头-----
Host: 127.0.0.1:8000\r\n
Connection: keep-alive\r\n
Content-Length: 26\r\n
Cache-Control: max-age=0\r\n
sec-ch-ua: "Microsoft Edge";v="119", "Chromium";v="119", "Not?A_Brand";v="24"\r\n
sec-ch-ua-mobile: ?0\r\n
sec-ch-ua-platform: "Windows"\r\n
Upgrade-Insecure-Requests: 1\r\n
Origin: http://127.0.0.1:8000\r\n
Content-Type: application/x-www-form-urlencoded\r\n
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\n
Sec-Fetch-Site: same-origin\r\n
Sec-Fetch-Mode: navigate\r\n
Sec-Fetch-User: ?1\r\n
Sec-Fetch-Dest: document\r\n
Referer: http://127.0.0.1:8000/\r\n
Accept-Encoding: gzip, deflate, br\r\n
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6\r\n
Cookie: o2State={%22webp%22:true%2C%22avif%22:false};csrftoken=X7rlh2l36LXbjh0COtpHqlaJOZFxjDzhbx8XPh0k9Ncl9in9VCemv4OIfyjFo1T4\r\n\r\n

------请求体-----
username=jack&password=123'
'''

响应式协议

响应格式

响应首行:HTTP/1.1 200 OK\r\n
协议版本
响应状态码
响应描述符

响应头:有K/V键值对组成

响应体:浏览器看到的页面都是响应体

Http有哪些版本

HTTP 0.9

HTTP 0.9 是最早发布出来的一个版本,于1991年发布。

它只接受 GET 一种请求方法,没有在通讯中指定版本号,且不支持请求头。由于该版本不支持 POST 方法,因此客户端无法向服务器传递太多信息。

HTTP 0.9 具有典型的无状态性,每个事务独立进行处理,事务结束时就释放这个连接。HTTP 协议的无状态特点在其第一个版本中已经成型。

HTTP 1.0

HTTP 1.0是HTTP协议的第二个版本,于1996年发布,如今仍然被广泛使用,尤其是在代理服务器中。

这是第一个在通讯中指定版本号的HTTP协议版本,具有以下特点:

  • 不仅仅支持 GET 命令,还支持 POST 和 HEAD 等请求方法。
    HTTP 的请求和回应格式也发生了变化,除了要传输的数据之外,每次通信都包含头信息,用来描述一些信息。
  • 不再局限于 0.9 版本的纯文本格式
    根据头信息中的 Content-Type 属性,可以支持多种数据格式,这使得互联网不仅仅可以用来传输文字,还可以传输图像、音频、视频等二进制文件。
  • 开始支持cache,就是当客户端在规定时间内访问同一网站,直接访问cache即可。
  • 其他的新增功能还包括状态码(status code)、多字符集支持、多部分发送(multi-part type)、权限(authorization)、缓存(cache)、内容编码(content encoding)等。
    1.0 版本的工作方式是每次 TCP 连接只能发送一个请求,当服务器响应后就会关闭这次连接,下一个请求需要再次建立 TCP 连接。 TCP 连接的建立成本很高,因为需要客户端和服务器三次握手,并且开始时发送速率较慢(slow start)。

HTTP 1.0 版本的性能比较差。随着网页加载的外部资源越来越多,这个问题就愈发突出了。为了解决这个问题,有些浏览器在请求时,即在请求头部加上 Connection 字段:

HTTP1.1

默认采用持续连接(Connection: keep-alive),能很好地配合代理服务器工作。
还支持以管道方式在同时发送多个请求,以便降低线路负载,提高传输速度。

HTTP 1.1 具有以下特点:

  • 引入了持久连接(persistent connection)
    即 TCP 连接默认不关闭,可以被多个请求复用,不用声明 Connection: keep-alive。客户端和服务器发现对方一段时间没有活动,就可以主动关闭连接。不过,规范的做法是,客户端在最后一个请求时,发送 Connection: close,明确要求服务器关闭 TCP 连接。
  • 加入了管道机制
    在同一个 TCP 连接里,允许多个请求同时发送,增加了并发性,进一步改善了 HTTP 协议的效率。
    举例来说,客户端需要请求两个资源。以前的做法是,在同一个 TCP 连接里面,先发送 A 请求,然后等待服务器做出回应,收到后再发出 B 请求。
    管道机制则是允许浏览器同时发出 A 请求和 B 请求,但是服务器还是按照顺序,先回应 A 请求,完成后再回应 B 请求。
    一个 TCP 连接现在可以传送多个回应,势必就要有一种机制,区分数据包是属于哪一个回应的。这就是 Content-length 字段的作用,声明本次回应的数据长度。
  • 分块传输编码
    使用 Content-Length 字段的前提条件是,服务器发送回应之前,必须知道回应的数据长度。对于一些很耗时的动态操作来说,这意味着,服务器要等到所有操作完成,才能发送数据,显然这样的效率不高。
    更好的处理方法是,产生一块数据,就发送一块,采用"流模式"(stream)取代"缓存模式"(buffer)。
    因此,HTTP 1.1 版本规定可以不使用 Content-Length 字段,而使用"分块传输编码"(chunked transfer encoding)。只要请求或回应的头信息有 Transfer-Encoding 字段,就表明回应将由数量未定的数据块组成。
  • 新增了请求方式 PUT、PATCH、OPTIONS、DELETE 等。
  • 客户端请求的头信息新增了 Host 字段,用来指定服务器的域名。
  • HTTP 1.1 支持文件断点续传,RANGE:bytes,HTTP 1.0 每次传送文件都是从文件头开始,即 0 字节处开始。RANGE:bytes=XXXX 表示要求服务器从文件 XXXX 字节处开始传送,断点续传。即返回码是 206(Partial Content)
HTTP/2.0

这也是最新的 HTTP 版本,于 2015 年 5 月作为互联网标准正式发布。

它具有以下特点:

  • 二进制协议
    HTTP 1.1 版的头信息肯定是文本(ASCII 编码),数据体可以是文本,也可以是二进制。
    HTTP 2.0 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧"(frame):头信息帧和数据帧。
  • 多工
    HTTP 2.0 复用 TCP 连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应,这样就避免了"队头堵塞"(HTTP 2.0 使用了多路复用的技术,做到同一个连接并发处理多个请求,而且并发请求的数量比 HTTP 1.1大了好几个数量级)。
    举例来说,在一个 TCP 连接里面,服务器同时收到了 A 请求和 B 请求,于是先回应 A 请求,结果发现处理过程非常耗时,于是就发送 A 请求已经处理好的部分, 接着回应 B 请求,完成后,再发送 A 请求剩下的部分。
  • 头信息压缩
    HTTP 协议不带有状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如 Cookie 和 User Agent,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。
    HTTP 2.0 对这一点做了优化,引入了头信息压缩机制(header compression)。一方面,头信息使用 gzip 或c ompress 压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了。
  • 服务器推送
    HTTP 2.0 允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送(server push)。意思是说,当我们对支持 HTTP 2.0 的 web server 请求数据的时候,服务器会顺便把一些客户端需要的资源一起推送到客户端,免得客户端再次创建连接发送请求到服务器端获取。这种方式非常合适加载静态资源。 服务器端推送的这些资源其实存在客户端的某处地方,客户端直接从本地加载这些资源就可以了,不用走网络,速度自然是快很多的。
HTTP/3.0

基于Google的QUIC,HTTP3 背后的主要思想是放弃 TCP,转而使用基于 UDP 的 QUIC 协议。

为了解决HTTP/2.0中TCP造成的队头阻塞问题,HTTP/3.0直接放弃使用TCP,将传输层协议改成UDP;但是因为UDP是不可靠传输,所以这就需要QUIC实现可靠机制

QUIC 也是需要三次握手来建立连接的,主要目的是为了确定连接 ID。
在 UDP 报文头部与 HTTP 消息之间,共有 3 层头部:
在这里插入图片描述
QUIC特点:
无队头阻塞
QUIC 协议也有类似 HTTP/2 Stream 与多路复用的概念,也是可以在同一条连接上并发传输多个 Stream,Stream 可以认为就是一条 HTTP 请求。

QUIC 有自己的一套机制可以保证传输的可靠性的。当某个流发生丢包时,只会阻塞这个流,其他流不会受到影响,因此不存在队头阻塞问题。这与 HTTP/2 不同,HTTP/2 只要某个流中的数据包丢失了,其他流也会因此受影响。

所以,QUIC 连接上的多个 Stream 之间并没有依赖,都是独立的,某个流发生丢包了,只会影响该流,其他流不受影响。

连接建立
HTTP/3 在传输数据前虽然需要 QUIC 协议握手,这个握手过程只需要 1 RTT,握手的目的是为确认双方的「连接 ID」,连接迁移就是基于连接 ID 实现的。
在这里插入图片描述

连接迁移
基于 TCP 传输协议的 HTTP 协议,由于是通过四元组(源 IP、源端口、目的 IP、目的端口)确定一条 TCP 连接,例如设备要连接wifi(IP地址改变)就必须要重新建立连接,而建立连接包含TCP三次握手和TSL四次握手,以及TCP慢启动所以会造成使用者卡顿的感觉

而QUIC通过连接ID标记自己,客户端和服务器可以各自选择一组 ID 来标记自己,因此即使移动设备的网络变化后,导致 IP 地址变化了,只要有上下文信息(比如连接 ID、TLS 密钥等),就可以“无缝”地复用原连接,消除重连的成本,没有丝毫卡顿感,达到了连接迁移的功能。

其实, QUIC 是一个在 UDP 之上的伪 TCP + TLS + HTTP/2 的多路复用的协议。

总结

HTTP/0.9:功能简陋,只支持GET方法,只能发送HTML格式字符串。

HTTP/1.0:支持多种数据格式,增加POST、HEAD等方法,增加头信息,每次只能发送一个请求(无持久连接)

HTTP/1.1:默认持久连接、请求管道化、增加缓存处理、增加Host字段、支持断点传输分块传输等。

HTTP/2.0:二进制分帧、多路复用、头部压缩、服务器推送

HTTP/3.0: 将传输层协议改成UDP;但是因为UDP是不可靠传输,所以这就需要QUIC实现可靠机制,QUIC 也是需要三次握手来建立连接的,主要目的是为了确定连接 ID。

常见的请求头

1. User-Agent:标识客户端使用的浏览器和操作系统信息。可以通过$_SERVER['HTTP_USER_AGENT']获取。

2. Accept:指定客户端能够处理的内容类型,即可接受的媒体类型。可以通过$_SERVER['HTTP_ACCEPT']获取。

3. Content-Type:指定请求体中的数据格式类型。常见的取值有application/json、application/x-www-form-urlencoded等。可以通过$_SERVER['CONTENT_TYPE']获取。

4. Authorization:用于进行身份验证的凭证信息。常见的取值有Bearer Token、Basic Authentication等。可以通过$_SERVER['HTTP_AUTHORIZATION']获取。

5. Cookie:包含来自客户端的Cookie信息。可以通过$_SERVER['HTTP_COOKIE']获取。

6. Referer:指示当前请求是从哪个URL页面发起的。可以通过$_SERVER['HTTP_REFERER']获取。、

8.Host:指定服务器的域名或IP地址。可以通过$_SERVER['HTTP_HOST']获取。

8. X-Requested-With:指示请求是否由Ajax发起的。通常在Ajax请求中会设置该头部字段,取值为"XMLHttpRequest"。可以通过$_SERVER['HTTP_X_REQUESTED_WITH']获取。

9. Content-Length:指定请求体的长度。可以通过$_SERVER['CONTENT_LENGTH']获取。

10. Cache-Control:控制缓存行为的指令。用于指定客户端和代理服务器如何缓存响应。可以通过$_SERVER['HTTP_CACHE_CONTROL']获取。

常见响应头

1.Cache-Control(对应请求中的Cache-Control)Cache-Control:private 默认为private  响应只能够作为私有的缓存,不能再用户间共享Cache-Control:public 浏览器和缓存服务器都可以缓存页面信息。Cache-Control:must-revalidate  对于客户机的每次请求,代理服务器必须想服务器验证缓存是否过时。Cache-Control:no-cache  浏览器和缓存服务器都不应该缓存页面信息。Cache-Control:max-age=10  是通知浏览器10秒之内不要烦我,自己从缓冲区中刷新。Cache-Control:no-store 请求和响应的信息都不应该被存储在对方的磁盘系统中。

2.Content-Type:text/html;charset=UTF-8 告诉客户端,资源文件的类型,还有字符编码,客户端通过utf-8对资源进行解码,然后对资源进行html解析。通常我们会看到有些网站是乱码的,往往就是服务器端没有返回正确的编码。

3.Content-Encoding:gzip 告诉客户端,服务端发送的资源是采用gzip编码的,客户端看到这个信息后,应该采用gzip对资源进行解码。

4.Date: Tue, 03 Apr 2018 03:52:28 GMT 这个是服务端发送资源时的服务器时间,GMT是格林尼治所在地的标准时间。http协议中发送的时间都是GMT的,这主要是解决在互联网上,不同时区在相互请求资源的时候,时间混乱问题。

5.Server:Tengine/1.4.6  这个是服务器和相对应的版本,只是告诉客户端服务器信息。

6.Transfer-Encoding:chunked 这个响应头告诉客户端,服务器发送的资源的方式是分块发送的。一般分块发送的资源都是服务器动态生成的,在发送时还不知道发送资源的大小,所以采用分块发送,每一块都是独立的,独立的块都能标示自己的长度,最后一块是0长度的,当客户端读到这个0长度的块时,就可以确定资源已经传输完了。

7.Expires:Sun, 1 Jan 2000 01:00:00 GMT 这个响应头也是跟缓存有关的,告诉客户端在这个时间前,可以直接访问缓存副本,很显然这个值会存在问题,因为客户端和服务器的时间不一定会都是相同的,如果时间不同就会导致问题。所以这个响应头是没有Cache-Control:max-age=*这个响应头准确的,因为max-age=date中的date是个相对时间,不仅更好理解,也更准确。

8.Last-Modified: Dec, 26 Dec 2015 17:30:00 GMT 所请求的对象的最后修改日期(按照 RFC 7231 中定义的“超文本传输协议日期”格式来表示)

9.Connection:keep-alive 这个字段作为回应客户端的Connection:keep-alive,告诉客户端服务器的tcp连接也是一个长连接,客户端可以继续使用这个tcp连接发送http请求。

10.EtagETag: "737060cd8c284d8af7ad3082f209582d" 就是一个对象(比如URL)的标志值,就一个对象而言,比如一个html文件,如果被修改了,其Etag也会别修改,所以,ETag的作用跟Last-Modified的作用差不多,主要供WEB服务器判断一个对象是否改变了。比如前一次请求某个html文件时,获得了其 ETag,当这次又请求这个文件时,浏览器就会把先前获得ETag值发送给WEB服务器,然后WEB服务器会把这个ETag跟该文件的当前ETag进行对比,然后就知道这个文件有没有改变了。

11.Refresh: 5; url=http://baidu.com  用于重定向,或者当一个新的资源被创建时。默认会在5秒后刷新重定向。

12.Access-Control-Allow-Origin: *   *号代表所有网站可以跨域资源共享,如果当前字段为*那么Access-Control-Allow-Credentials就不能为trueAccess-Control-Allow-Origin: www.baidu.com 指定哪些网站可以跨域资源共享

13.Access-Control-Allow-Methods:GET,POST,PUT,DELETE  允许哪些方法来访问

14.Access-Control-Allow-Credentials: true  是否允许发送cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。如果access-control-allow-origin为*,当前字段就不能为true

15.Content-Range: bytes 0-5/7877 指定整个实体中的一部分的插入位置,他也指示了整个实体的长度。在服务器向客户返回一个部分响应,它必须描述响应覆盖的范围和整个实体长度。

常见的响应状态码

HTTP状态码负责表示客户端HTTP请求的返回结果、标记服务器的处理是否正常、通知出现的错误工作等。借助状态码,用户可以知道服务器端是正常处理了请求,还是出现了错误。
在这里插入图片描述

状态码如200 OK,由3位数字和原因短语组成。数字中的第一位指定了响应类别,后两位无分类。相应类别由以下五种:

1xx Informational(信息状态码) 接受请求正在处理
2xx Success(成功状态码) 请求正常处理完毕
3xx Redirection(重定向状态码) 需要附加操作已完成请求
4xx Client Error(客户端错误状态码) 服务器无法处理请求
5xx Server Error(服务器错误状态码) 服务器处理请求出错

HTTP的状态码总数达60余种,但是常用的大概只有14种。接下来,我们就介绍一下这些具有代表性的14个状态码。

200 OK 请求成功。一般用于GET与POST请求

204 No Content 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档

206 Partial Content 是对资源某一部分的请求,服务器成功处理了部分GET请求,响应报文中包含由Content-Range指定范围的实体内容。

301 Moved Permanently 永久性重定向。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替

302 Found 临时性重定向。与301类似。但资源只是临时被移动。客户端应继续使用原有URI

303 See Other 查看其它地址。与302类似。使用GET请求查看

304 Not Modified 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源

307 Temporary Redirect 临时重定向。与302类似。使用GET请求重定向,会按照浏览器标准,不会从POST变成GET。

400 Bad Request 客户端请求报文中存在语法错误,服务器无法理解。浏览器会像200 OK一样对待该状态吗

401 Unauthorized 请求要求用户的身份认证,通过HTTP认证(BASIC认证,DIGEST认证)的认证信息,若之前已进行过一次请求,则表示用户认证失败

402 Payment Required 保留,将来使用

403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求

404 Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面。也可以在服务器拒绝请求且不想说明理由时使用

500 Internal Server Error 服务器内部错误,无法完成请求,也可能是web应用存在bug或某些临时故障

501 Not Implemented 服务器不支持请求的功能,无法完成请求

503 Service Unavailable 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中

web框架

1.web框架是什么

简单来说就是别人帮咱写了一些基础代码,我们只需要在固定位置写固定的代码,就能实现一个web应用

Web框架(Web framework)是一种开发框架,用来支持动态网站、网络应用和网络服务的开发。这大多数的web框架提供了一套开发和部署网站的方式,也为web行为提供了一套通用的方法。web框架已经实现了很多功能,开发人员使用框架提供的方法并且完成自己的业务逻辑,就能快速开发web应用了。浏览器和服务器的是基于HTTP协议进行通信的。也可以说web框架就是在以上十几行代码基础张扩展出来的,有很多简单方便使用的方法,大大提高了开发的效率

2.wsgi协议

客户端浏览器和python web框架之间通讯需要遵守这个协议,客户端发出的是http请求,通过符合wsgi协议的web服务器通讯

应用程序,是一个可重复调用的可调用对象,在Python中可以是一个函数,也可以是一个类,如果是类的话要实现__call__方法,要求这个可调用对象接收2个参数,返回一个内容结果

接收的2个参数分别是environ和start_response。

environ是web服务器解析HTTP协议的一些信息,例如请求方法,请求URI等信息构成的一个Dict对象。
start_response是一个函数,接收2个参数,一个是HTTP状态码,一个HTTP消息中的响应头。

Django

1.MVC与MTV模型

所有的web框架都是遵守MVC架构

MVC

将写在一个文件里的代码,拆分到不同的位置

模型(M:数据层)
控制器(C: 逻辑判断)
视图(V: 用户看到的)

他们之间以一种插件式的、松耦合的方式连接在一起,模型负责业务对象与数据库的映射(ORM),视图负责与用户的交互(页面),控制器接受用户的输入调用模型和视图完成用户的请求

MTV

M 代表模型(Model): 负责业务对象和数据库的关系映射(ORM)。
M就是原来的M
T 代表模板 (Template):负责如何把页面展示给用户(html)。
T就是原来的V
V 代表视图(View): 负责业务逻辑,并在适当时候调用Model和Template
V+路由 是原来的C

3. 下载与使用

下载…

命令创建项目
django-admin startproject 项目名

命令创建应用
python manage.py startapp 应用名

4.django框架的目录结构

在这里插入图片描述

5.启动项目

  1. python manage.py runserver 127.0.0.1:8000
  2. 在pycharm中点击运行,注意切换到django项目运行

6.django请求生命周期图

在这里插入图片描述

路由控制

1.路由是什么

URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表;你就是以这种方式告诉Django,对于客户端发来的某个URL调用哪一段逻辑代码对应执行
请求路径和要执行的视图函数的对应关系

2.如何使用

path:准确路径,精准匹配-------->以后基本都是path
re_path----就是1.xx版本的url------>支持正则匹配----->不安全,非常少用

都是放在setting下的urlpatterns=[]列表中,必须是path或re_path执行完的结果

3. path详细使用

path(‘admin/’,login)等价于_path(route, view, kwargs=None, name=None)

第一个参数:
准确路径,字符串
转换器:‘<int:pk>’ , ‘<str:name>’
127.0.0.1:8080/login/jack---->path(‘login/<str:name>’, views.login)
视图函数:def login(request,name)

第二个参数:
视图函数的内存地址,不能加括号
路由一旦匹配成功,就会执行你写的这个视图函数加上(),并且把request对象传入

如果有分组的参数[有名,无名],或者转换器的参数,都会被传递到视图函数中作为参数

总结:放要放视图函数地址—》但是视图函数的参数:第一个是固定必须是request,后续的取决于写没写转换器,写没写有名无名分组

第三个参数:kwargs 是给视图函数传递默认参数

第四个参数:路径的别名—》后期使用反向解析得到该路径

re_path的详细使用

跟path除了第一个参数不一样,其他完全一样
第一个参数是正则表达式
后期用的很少,危险性大—》原来之所以支持正则的目的是为了分组出参数
path通过转换器能完成这个操作–》于是–》这个几乎不用

5.反向解析,用在视图函数中,用在模版中

需要导入reverse模块

  • 没有转换器的情况:
    path(‘login/’, login,name=‘login’)
    res=reverse(‘login’) #当时 定义路径传入的name参数对应的字符串
  • 有转换器的情况:
    path(‘login/<str:name>’, login,name=‘login’)
    res=reverse(‘login’,kwargs={name:jack}) #当时 定义路径传入的name参数对应的字符串
    生成这种路径:‘login/jack’

6.路由分发

每一个app有自己的路由
导入模块 from django.urls import include

视图层

1.views.py这个文件就是写视图函数的

2.视图函数编写

def 视图函数(request):
return 四件套

3.request对象

它是http请求对象(数据包,字符串形式)拆分成了django中得request对象

常用的有:
request.path
reuqest.method
request.GET
request.POST
reuqest.body
reqeust.get_full_path()
request.files 前端传过来文件,转成字典,根据文件的名字取到文件对象

不常用的
reqeust.cookie
request.session
request.contnet_type
request.MEAT:请求头中的数据

user-agent:HTTP_USER_AGENT
referer:
客户端IP地址:REMOTE_ADDR
用户自定义的
定义:name=jack
取:request.META.get('HTTP_NAME')# 前面加HTTP_ 把自定义的转成大写

request.user

request.is_ajax()

响应对象

响应对象的本质都是 HttpResponse

响应对象四件套:
  1. HttpResponse 字符串

  2. render 需要返回两个必传参数,一个是request,一个是模板,模板渲染是在后端完成,模板返回到浏览器,最终成为响应体,还可以传其他参数,可以去看源码。
    模版渲染是在后端完成的,而js代码是在客户端渲染完成。
    js想要用python中的变量,就需要使用模板语法

  3. redirect 重定向
    没有放字符串的位置
    状态码是3开头

  4. JsonResponse json格式数据
    需要另外导入:from django.http import JsonResponse

读JsonResponse源码
1.现在返回一个JsonResponse({'name':'jack'})

 def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,json_dumps_params=None, **kwargs):
2.{'name':'jack'}就会传给data
        if safe and not isinstance(data, dict):
3.判断safe成立,如果想返回一个列表,把safe改成False
   isinstance,检查对象是否成立(对象,类)
   所以以上if不成立,就不会走下面的代码
            raise TypeError(
                'In order to allow non-dict objects to be serialized set the '
                'safe parameter to False.'
            )
        if json_dumps_params is None:
            json_dumps_params = {}
        kwargs.setdefault('content_type', 'application/json')
4.默认的请求头,setdefault,有则修改,无则新增
        data = json.dumps(data, cls=encoder, **json_dumps_params)
5.这一句才是将数据序列化成json格式       
        super().__init__(content=data, **kwargs)
6.调用父类的__init__完成实例化得到一个HttpResponse的对象



现在传一个{'name':'张三'}
序列化的时候就需要转码:json.dump({'name':'张三'}, ensure_ascii=False)这样子才能是中文


而在JsonResponse中,是不能用ensure_ascii=False
而是用:
JsonResponse({'name':'张三'},json_dumps_params={'ensure_ascii':False})


''''''''''''''''''''''
还可以添加响应头,需要用到headers参数
JsonResponse({'name':'张三'},json_dumps_params={'ensure_ascii':False},headers={'xxx':'xxx'})

CBV和FBV

FBV:基于函数的视图,经常写的都是FBV
CBV:基于类的视图,后续全是CBV

CBV写法
class UseView(View):
    def get(self,request):
        return HttpResponse('from get')

    def post(self,request):
        return HttpResponse('from post')

路由配置

path('index/', views.UseView.as_view())
CBV的执行流程

先去路由匹配,匹配成功执行,UserView.as_view(),一定会执行(request)

as_view()代码执行结果

        def view(request, *args, **kwargs):   本质就是在执行view(request)
            self = cls(**initkwargs)
            self.setup(request, *args, **kwargs)
            if not hasattr(self, 'request'):
                raise AttributeError(
                    "%s instance has no 'request' attribute. Did you override "
                    "setup() and forget to call super()?" % cls.__name__
                )
            return self.dispatch(request, *args, **kwargs)
            实际上是在执行self.dispatch(request, *args, **kwargs),又会去类中找dispatch

dispatch代码:

    def dispatch(self, request, *args, **kwargs):
        if request.method.lower() in self.http_method_names:  request请求来请求对象时,会在8大请求方法里找
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
            # getattr 反射方法 通过字符串去对象中取属性或方法
			# self是谁调用的就是谁的对象
			# handler取出来的是Userview这个类的get方法
			
        else:
            handler = self.http_method_not_allowed
            
            get(request)就会执行UserView这个类的get方法,才会真正执行原来的视图函数的内容
        return handler(request, *args, **kwargs)

总结:写CBV,只需要在视图类写请求方式同名的方法即可,不同的请求方式,就会执行不同的方法

关于类中self是谁的问题

谁在调用就是谁

模板层

1.介绍

模版在浏览器中是运行不了的,因为他有固定的语法,浏览器是解析不了模板语法的,需要在后端被渲染,类似python语法,所以我们可以使用django的模板系统(template system)来实现这种模式

python的模板:HTML代码+模板语法

django模版修改的视图函数

from django.template import Template,Context   需要导入两个模块
import datetime
now=datetime.datetime.now()   得到一个时间对象
t=Template('<html><body>现在时刻是:<h1>{{current_date}}</h1></body></html>')  内部打开了这个模板---》读出所有内容,实例化得到了t对象
c=Context({'current_date':str(now)})
html=t.render(c)
return HttpResponse(html)

另一种写法(推荐):

import datetime
now = datetime.datetime.now()
return render(request, 'current_datetime.html',{'crrent_date':str(now)[:19]})

总结:

render(request,'模板名字',context={key:value,key1:value})
本质是:
t=Template('<html><body>现在时刻是:<h1>{{current_date}}</h1></body></html>')
c=Context({'current_date':str(now)})
html=t.render(c) # 返回是字符串
HttpResponse(html)

2.页面静态化

页面静态化有什么作用:提高项目的并发量,响应速度高和效率就高了,这样就不用每次访问页面去数据库中调取页面
把什么页面做成静态化:一般是首页,也就是访问量高的页面。

下面做一个静态化的页面:


def static_page(request):
1.首先判断文件夹下有没有staticpage123.html纯静态页面
    if not os.path.exists(r'E:\MyDjango\csrf假\templates\staticpage123.html'):
2.如果没有则执行该代码
        user_obj = models.UserInfo.objects.all()  # 前端需要通过这条语句来查询,并显示出来
        with open('templates/staticpage.html', 'r') as f:  # 这是读该文件夹下的动态页面
            # print(f.read())
            t = Template(f.read())  # 内部读出该文件并得到一个对象
            c = Context(locals())  # 将模版语法传入到上下文管理器中,locals()获取页面上所有对象,等价于{'user_obj':user_obj}
            html = t.render(c)   # 读出来的页面加上上下文管理中的模板语法,得到一个字符串对象
        with open('templates/'+'staticpage123.html', 'w')as f1:  # 这一句才是在写出来静态页面
            f1.write(html)  # 将html字符串对象写入到staticpage123.html中,这就是我们的静态文件
        return HttpResponse(html)  # HttpResponse可以直接返回一个字符串对象
    else:
        # 如果存在静态文件返回静态文件
        return render(request,'staticpage123.html')

模板语法

变量插值:
使用双括号 {{ variable }} 将变量插入到模板中。例如:{{ user.username }}

标签:
使用括号和百分号 {% %} 包裹的内容是标签。标签用于控制模板的流程和逻辑,如条件语句、循环等。例如:{% if user.is_authenticated %} ... {% endif %}

过滤器:
使用管道符 | 将变量传递给过滤器,以对变量进行处理。例如:{{ value|filter_name }}

注释:
使用 {# 注释内容 #} 进行注释。

模板继承:
使用 {% extends "base_template.html" %} 来继承其他模板。

块:
使用 {% block content %}...{% endblock %} 定义可被子模板覆盖的块。

循环:
使用 {% for item in list %}...{% endfor %} 进行循环迭代。

条件语句:
使用 {% if condition %}...{% elif another_condition %}...{% else %}...{% endif %} 进行条件判断。

包含:
使用 {% include "partial_template.html" %} 包含其他模板。

URL反解析:
使用 {% url 'url_name' arg1 arg2 %} 生成URL。

静态文件引用:
使用 {% load static %} 导入静态文件,然后使用 {% static 'path/to/file.css' %} 引用静态文件。

模板语法重点:

变量:{{ 变量名 }}
1 深度查询 用句点符
2 过滤器
3 标签:{{% % }}

过滤器使用
1.在某个app下:创建一个templatetags包,在包里创建一个py文件
2.在py文件中写过滤器

导入模块
from django import template
register = timplate.Library()  register 的名字是固定的,不可改变
定义一个自己的过滤器标签
@register.filter
def my_filter(content:str)->str:   # 在括号里加str和在外面加str的作用是一样的,表示我的content是一个字符串
	l = ['妈的', '傻逼', '退游']  # 定义一个列表,列表里放的是我需要屏蔽的关键词
	# 解下来循环l列表:把content中的所有关键词替换,然后返回
	for item in l:
		content = content.replace(item,'**')
	return content

前端要调用过滤器标签的话就需要加载templatetags包下的py文件
{% load 文件名 %}

过滤器用法
{{ 需要替换的内容变量或对象|my_filter }}

模型层

ORM介绍

查询数据层次图解:如果操作mysql,ORM是在pymysql之上又进行了一层封装
在这里插入图片描述

1ORM是对象-关系-映射的简称

在数据库中是一个个的表,一条条记录
在程序中是一个个的类和一个个的对象

2.SQL中的表

 #创建表:
     CREATE TABLE employee(                                     
                id INT PRIMARY KEY auto_increment ,                    
                name VARCHAR (20),                                      
                gender BIT default 1,                                  
                birthday DATA ,                                         
                department VARCHAR (20),                                
                salary DECIMAL (8,2) unsigned,                          
              );


  #sql中的表纪录                                                  

  #添加一条表纪录:                                                          
      INSERT employee (name,gender,birthday,salary,department)            
             VALUES   ("lqz",1,"1985-12-12",8000,"保洁部");               

  #查询一条表纪录:                                                           
      SELECT * FROM employee WHERE age=24;                               

  #更新一条表纪录:                                                           
      UPDATE employee SET birthday="1989-10-24" WHERE id=1;              

  #删除一条表纪录:                                                          
      DELETE FROM employee WHERE name="lqz"                             





#python的类
class Employee(models.Model):
     id=models.AutoField(primary_key=True)
     name=models.CharField(max_length=32)
     gender=models.BooleanField()
     birthday=models.DateField()
     department=models.CharField(max_length=32)
     salary=models.DecimalField(max_digits=8,decimal_places=2)


 #python的类对象
      #添加一条表纪录:
          emp=Employee(name="lqz",gender=True,birthday="1985-12-12",epartment="保洁部")
          emp.save()
      #查询一条表纪录:
          Employee.objects.filter(age=24)
      #更新一条表纪录:
          Employee.objects.filter(id=1).update(birthday="1989-10-24")
      #删除一条表纪录:
          Employee.objects.filter(name="lqz").delete()

在pycharm中建表还需要执行数据迁移的命令
python manage.py makemigrations
python manage.py migrate

2.常用字段和非常用字段

AutoField(Field)
    - int自增列,必须填入参数 primary_key=True

BigAutoField(AutoField)
    - bigint自增列,必须填入参数 primary_key=True
    注:当model中如果没有自增列,则自动会创建一个列名为id的列
    from django.db import models
    class UserInfo(models.Model):
        # 自动创建一个列名为id的且为自增的整数列
        username = models.CharField(max_length=32)
    class Group(models.Model):
        # 自定义自增列
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
SmallIntegerField(IntegerField):
    - 小整数 -3276832767

PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
    - 正小整数 032767
IntegerField(Field)
    - 整数列(有符号的) -21474836482147483647

PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
    - 正整数 02147483647

BigIntegerField(IntegerField):
    - 长整型(有符号的) -92233720368547758089223372036854775807

自定义无符号整数字段
	class UnsignedIntegerField(models.IntegerField):
 	    def db_type(self, connection):
	        return 'integer UNSIGNED'

    PS: 返回值为字段在数据库中的属性,Django字段默认的值为:
        'AutoField': 'integer AUTO_INCREMENT',
        'BigAutoField': 'bigint AUTO_INCREMENT',
        'BinaryField': 'longblob',
        'BooleanField': 'bool',
        'CharField': 'varchar(%(max_length)s)',
        'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
        'DateField': 'date',
        'DateTimeField': 'datetime',
        'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
        'DurationField': 'bigint',
        'FileField': 'varchar(%(max_length)s)',
        'FilePathField': 'varchar(%(max_length)s)',
        'FloatField': 'double precision',
        'IntegerField': 'integer',
        'BigIntegerField': 'bigint',
        'IPAddressField': 'char(15)',
        'GenericIPAddressField': 'char(39)',
        'NullBooleanField': 'bool',
        'OneToOneField': 'integer',
        'PositiveIntegerField': 'integer UNSIGNED',
        'PositiveSmallIntegerField': 'smallint UNSIGNED',
        'SlugField': 'varchar(%(max_length)s)',
        'SmallIntegerField': 'smallint',
        'TextField': 'longtext',
        'TimeField': 'time',
        'UUIDField': 'char(32)',

BooleanField(Field)
    - 布尔值类型

NullBooleanField(Field):
    - 可以为空的布尔值

CharField(Field)
    - 字符类型
    - 必须提供max_length参数, max_length表示字符长度

TextField(Field)
    - 文本类型

EmailField(CharField)- 字符串类型,Django Admin以及ModelForm中提供验证机制

IPAddressField(Field)
    - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制

GenericIPAddressField(Field)
    - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
    - 参数:
        protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
        unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启刺功能,需要protocol="both"

URLField(CharField)
    - 字符串类型,Django Admin以及ModelForm中提供验证 URL

SlugField(CharField)
    - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)

CommaSeparatedIntegerField(CharField)
    - 字符串类型,格式必须为逗号分割的数字

UUIDField(Field)
    - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证

FilePathField(Field)
    - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
    - 参数:
            path,                      文件夹路径
            match=None,                正则匹配
            recursive=False,           递归下面的文件夹
            allow_files=True,          允许文件
            allow_folders=False,       允许文件夹

FileField(Field)
    - 字符串,路径保存在数据库,文件上传到指定目录
    - 参数:
        upload_to = ""      上传文件的保存路径
        storage = None      存储组件,默认django.core.files.storage.FileSystemStorage

ImageField(FileField)
    - 字符串,路径保存在数据库,文件上传到指定目录
    - 参数:
        upload_to = ""      上传文件的保存路径
        storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
        width_field=None,   上传图片的高度保存的数据库字段名(字符串)
        height_field=None   上传图片的宽度保存的数据库字段名(字符串)

DateTimeField(DateField)
    - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]

DateField(DateTimeCheckMixin, Field)
    - 日期格式      YYYY-MM-DD

TimeField(DateTimeCheckMixin, Field)
    - 时间格式      HH:MM[:ss[.uuuuuu]]

DurationField(Field)
    - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型

FloatField(Field)
    - 浮点型

DecimalField(Field)
    - 10进制小数
    - 参数:
        max_digits,小数总长度
        decimal_places,小数位长度

BinaryField(Field)
    - 二进制类型

3.常用字段与非常用字段参数

(1)null
 
如果为True,Django 将用NULL 来在数据库中存储空值。 默认值是 False.
 
(1)blank
 
如果为True,该字段允许不填。默认为False。
要注意,这与 null 不同。null纯粹是数据库范畴的,而 blank 是数据验证范畴的。
如果一个字段的blank=True,表单的验证将允许该字段是空值。如果字段的blank=False,该字段就是必填的。
 
(2)default
 
字段的默认值。可以是一个值或者可调用对象。如果可调用 ,每有新对象被创建它都会被调用。
 
(3)primary_key
 
如果为True,那么这个字段就是模型的主键。如果你没有指定任何一个字段的primary_key=True,
Django 就会自动添加一个IntegerField字段做为主键,所以除非你想覆盖默认的主键行为,
否则没必要设置任何一个字段的primary_key=True(4)unique
 
如果该值设置为 True, 这个数据字段的值在整张表中必须是唯一的
 
(5)choices
由二元组组成的一个可迭代对象(例如,列表或元组),用来给字段提供选择项。 如果设置了choices ,默认的表单将是一个选择框而不是标准的文本框,<br>而且这个选择框的选项就是choices 中的选项。
class UserInfo(models.Model):
       nid = models.AutoField(primary_key=True)
       username = models.CharField(max_length=32)
       class Meta:
           # 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
           db_table = "table_name"

           # 联合索引
           index_together = [
               ("pub_date", "deadline"),
           ]

           # 联合唯一索引
           unique_together = (("driver", "restaurant"),)

           # admin中显示的表名称
           verbose_name

           # verbose_name加s
           verbose_name_plural

4.settings配置

配置文件中的配置
默认操作的是sqlite
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite_lqz',
    }
}


操作mysql:
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'day05',
        'HOST':'127.0.0.1',
        'PORT':3306,
        'USER':'root',
        'PASSWORD':'1234',
    }
}

装模块:pymysql,mysqlclient

mysqlclient,有可能装不上,看人品

没有mysqlclient就需要在__init__文件中加上以下代码

import pymysql
pymysql.install_as_MySQLdb()

5.基本操作(增删改查)

# 增加删除字段,只需要在表模型,增加,注释字段,增加删除字段参数,再迁移就可以了
	-不要轻易删除迁移记录
    
    
# 增加表记录
	# 方案一:
	Book.object.create()
    #方案二:
    book=Book(参数)
    book.save()
    
    
    
# 删除记录
	-删除方式一:查出来再删
    	Book.objects.all().delete()
    -删除方式二:
    	#可以重写类中得delete方法
    	book=Book.objects.filter(pk=1).first()
        book.delete() #Book 类中有个delete方法,咱们没有写---》父类的--》可以重写
# 更新
	-更新方式一:查出来再删
    	Book.objects.all().update()
    -更新方式二:	
        book=Book.objects.filter(pk=1).first()
        book.name='ss'
        book.save()
        
#查
# all():                  查询所有结果
# filter(**kwargs):       它包含了与所给筛选条件相匹配的对象
# get(**kwargs):          返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
  
# exclude(**kwargs):      它包含了与所给筛选条件不匹配的对象
 
# order_by(*field):       对查询结果排序('-id')
  
# reverse():              对查询结果反向排序
  
# count():                返回数据库中匹配查询(QuerySet)的对象数量。
  
# first():                返回第一条记录
  
# last():                返回最后一条记录
  
# exists():              如果QuerySet包含数据,就返回True,否则返回False
 
#values(*field):        返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列
                            model的实例化对象,而是一个可迭代的字典序列
#values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
 
# distinct():            从返回结果中剔除重复纪录

6.多表操作,创建关系

class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish_date = models.DateField()
    publish = models.ForeignKey(to='Publish',on_delete=models.CASCADE)
    #这不是个字段
    authors=models.ManyToManyField(to='Author')
    def __str__(self):
        return self.name


class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    author_detail = models.OneToOneField(to='AuthorDatail',unique=True,on_delete=models.CASCADE)

class AuthorDatail(models.Model):
    telephone = models.BigIntegerField()
    birthday = models.DateField()
    addr = models.CharField(max_length=64)

class Publish(models.Model):
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    email = models.EmailField()
    
# 关联关系有如下几种
	- 一对一:本质就是一对多,只不过多的字段唯一
    -一对多:外键关联
    -多对多:必须要有中间表
    
    
    
#  OneToOneField,ForeignKey 必须写on_delete,不写报错
	on_delete可选的参数有哪些
    	#1 models.CASCADE  级联删除---》删除出版社---》当前出版社下所有的图书数据都会被删除
    	#2  models.SET_NULL 删除出版社---》当前出版社下所有的图书数据都会的publish_id字段都是置为空
    	publish = models.ForeignKey(to='Publish',on_delete=models.SET_NULL,null=True)
        #3  models.SET_DEFAULT 删除出版社---》当前出版社下所有的图书数据都会的publish_id字段都设为默认值
        publish = models.ForeignKey(to='Publish',on_delete=models.SET_DEFAULT,default=1)
        #4  models.SET(值/可调用对象)删除出版社---》当前出版社下所有的图书数据都会的publish_id字段都设为SET传入的值,如果是可调用对象,会执行可调用对象,把return变
       # 5 models.DO_NOTHING 删除出版社---》当前出版社下所有的图书数据都会的publish_id字段 原封不动
    	publish = models.ForeignKey(to='Publish',on_delete=models.DO_NOTHING,db_constraint=False)
    
    

7.基于对象的跨表查询

# 假设拿到book对象
	book.name
    book.price
    book.publish_id ---->数字---》出版社id---》咱们可以通过出版社id,再去出版社表,查出当前出版社---》很麻烦
    -----快捷方式-----
    book.publish---->拿到的是   publish对象---》当前图书的出版社对象
    book.publish.继续往后点击
    
# 上面这种查询方式,称之为基于对象的跨表查询
	对象=对象.字段
    publish=book.pulish

    
# 有正向查询和 反向查询---》拿到的都是对象
	-正向:当前表中,有那个字段,类似于:book.pulish   author.author_detail
    	-通过字段
    -反向:当前表中,没有那个字段	  author_detail.author  
    	通过author_detail拿到author
        -通过表名小写
        
     
# 一对一正反向
	太简单
# 一对多和多对多的正反向
    # 正向简单
    	publish=book.pulish
    # 反向
        publish对象---》拿到当前publish对象下所有出版过的图书-->反向查询
        puhlish.book_set.all() # 如果是反向,多条,就要用  表名小写_set.all()
    
#  多对多正反向
	# 正向: 拿到当前图书所有作者
    book.authors.all()  # 正向--》对象.字段.all()
    # 反向  拿到当前作者写的所有图书
    author.book_set.all() #反向--》多条,就要用  表名小写_set.all()

查找练习


import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_05.settings')
import django
django.setup()
from app01.models import Book,Author,AuthorDatail,Publish
if __name__ == '__main__':
    #res=Book.objects.all().values("title",'price')  # select title,price---》qs中套字典 有key,有value
    # res=Book.objects.all().values_list("title",'price')  # select title,price---》qs中套元组,只有value
    # print(res)

    ### 一对一正反向

    # 正向:
    # author = Author.objects.all().first()
    # print(author.author_detail.addr)

    # 反向
    # author_detail=AuthorDatail.objects.filter(pk=3).first()
    # print(author_detail.author.name)


    # 一对多
    # 正向:
    # book=Book.objects.all().first()
    # print(book.publish.name)

    # 反向
    # publish=Publish.objects.filter(pk=2).first()
    # print(publish.book_set.all())


    # 多对多
    # 正
    # book=Book.objects.filter(pk=3).first()
    # book=Book.objects.filter(pk=2).first()
    # print(book.authors.all())

    # 反
    # author=Author.objects.all().first()
    # print(author.book_set.all())

8.基于链表的跨表查询

一对一链表

拿出id1的作者(作者表)   的地址(作者详情表)

正向---》字段名 author_detail
res=Author.objects.filter(pk=1).values('id','name','age','author_detail__addr')
print(res)

反向---》查询 作者地址是 北京 的作者名和作者年龄
反向--》表名小写
res=AuthorDatail.objects.filter(addr='北京').values('addr','author__name','author__age')
print(res)

一对多正反向

查询北京出版社出版过的所有书籍的名字与价格(一对多):表名小写
res=Publish.objects.filter(name='北京出版社').values('name','book__name','book__price')
print(res)

正: 按字段
res=Book.objects.filter(publish__name='北京出版社').values('publish__name','name','price')
print(res)

多对多正反向

查询jack出过的所有书籍的名字(多对多)

反:
res=Author.objects.filter(name='jack').values("name","book__name")


正:
res=Book.objects.filter(authors__name='jack').values('authors__name','name')


查询红楼梦这本书出版社的名字
res=Book.objects.filter(title='红楼梦').values('publish__name')


查询北京出版社出版过的所有书籍的名字以及作者的姓名
res=Publish.objects.filter(name='北京出版社').values('book__name','book__authors__name','book__authors__author_detail__addr')

res=Book.objects.filter(publish__name='北京出版社').values('name','authors__name')
 
res = Author.objects.filter(book__publish__name='北京出版社').values('book__name','name')

9.聚合查询

aggregate()是QuerySet的一个终止子句,意思是说,返回一个包含一些键值对的字典。建的名称是聚合值的表示符,值实际算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。如果你想要为聚合值指定一个名称,可以向聚合子句提供它。

聚合函数

Avg,Max,Min,Sum,Count

在MySQL中的使用

 select avg(price) from app01_carmodel;
 select count(price) from app01_carmodel;
 select sum(price) from app01_carmodel;
 select min(price) from app01_carmodel;
 select max(price) from app01_carmodel;
在Django中使用

使用的时候需要导入聚合函数

from django.db.models import Avg,Max,Min,Sum,Count
查询图书价格平均值
Book.objects.aggregate(average_price=Avg('price'))
#{'average_price': 34.35}

还可以查询多个聚合函数,可以向aggregate()子句中添加另一个参数。所以,如果你也想知道所有图书价格的最大值和最小值,可以这样查询:

# 查询所有书籍的平均价格
from django.db.models import Avg,Count,Max,Min
ret=Book.objects.all().aggregate(Avg('price'))
# {'price__avg': 202.896}
# 可以改名字
ret=Book.objects.all().aggregate(avg_price=Avg('price'))
# 统计平均价格和最大价格
ret=Book.objects.all().aggregate(avg_price=Avg('price'),max_price=Max('price'))
# 统计最小价格
ret = Book.objects.all().aggregate(avg_price=Avg('price'), min_price=Min('price'))
# 统计个数和平均价格
ret = Book.objects.all().aggregate(avg_price=Avg('price'), max_price=Max('price'),count=Count('price'))
ret = Book.objects.all().aggregate(avg_price=Avg('price'), max_price=Max('price'),count=Count('nid'))
print(ret)

分组查询

分组通常会用到聚合函数,annotate用来分组和聚合
annotate:
filter在annotate前:表示过滤,where条件
values在annotate前:表示是分组的字段,如果不写表示按整个表分组
filter在annotate后:表示having条件
values在annotate后:表示取字段,只能去分组字段和聚合函数字段

分组的目的:把有相同特征的分成一组,分成一组后一般用来统计总条数,统计平均数,求最大值

统计每一本书作者个数
res = models.Book.objects.values('id').annotate(author_num=Count('authors')).values('authors__name', 'title')
print(res)
# 统计每一个出版社的最便宜的书
res = models.Publish.objects.values('id').annotate(min_price=Min('book__price')).values('name', 'book__price')
print(res)

# 查询每一个以 红开头 书籍的名称,以及对应的作者个数-->按书分
res = models.Book.objects.filter(title__startswith='西').values('id').annotate(count_publish=Count("authors")).values('authors__name','title')
print(res)

ORM字段参数

null用于表示某个字段可以为空。

unique 如果设置为unique=True 则该字段在此表中必须是唯一的 。

db_index如果db_index=True 则代表着为此字段设置索引。

default为该字段设置默认值。

DateField和DateTimeField 时间
- auto_now_add=True:新增会把当前时间存入
- default=datatime.datatime.now
- auto_now=True,每次更新数据记录的时候会更新该字段

on_delete

当删除关联表中的数据时,当前表与其关联的行的行为。

在这里插入代码片  # models.CASCADE删除关联数据,与之关联也删除
models.DO_NOTHING 删除关联数据,引发错误IntegrityError
models.PROTECT 删除关联数据,引发错误ProtectedError
models.SET_NULL删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
models.SET_DEFAULT删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)

models.SET
删除关联数据,
  a. 与之关联的值设置为指定值,设置:models.SET()
  b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)

db_constraint: 公司一般都设置为False
是否在数据库中创建外键约束,默认为True
db_constraint=False 在数据库中不建立外键约束
虽然不建立数据库外键约束—》但是orm查询,继续用

MySQL中的连表方式有哪些

有左连接、右连接、内连接、全连接、笛卡尔积
上面讲的都是连表方式,我们连表的目的是为了查询数据,而连表的依据是表和表之间要有的关系,这个关系就是外键关系

现在我有两张表,一个是图书表Book,一个是出版社表Publish

图书表 book
id   name   price   publish_id
1    西游记   33      1
2    红楼梦   56      1
3    三国     66      2
4    西厢记   55      6           # 脏数据,这个是在我的出版社里不存在的




出版社表 publish
id    name         addr
1     北京出版社    北京
2      南京出版社   南京
3      东京出版社   东京

左连接

select * from book left join publish on book.publish_id=publish.id;
id   name   price   publish_id   id    name         addr
1    西游记   33      1           1     北京出版社    北京
2    红楼梦   56      1           1     北京出版社    北京
3    三国     66      2           2      南京出版社   南京
4    西厢记   55      6           null     null      null

将两张表的的数据以左表为基准连接,左表的数据全部展示,右表没有的就用null填充

右连接

select * from book right join publish on book.publish_id=publish.id;
id   name   price   publish_id    id    name         addr
1    西游记   33      1            1     北京出版社    北京
2    红楼梦   56      1            1     北京出版社    北京
3    三国     66      2            2      南京出版社   南京
null  null   null     null	       3      东京出版社   东京  

将两张表的的数据以右表为基准连接,右表的数据全部展示,左表没有的就用null填充

内连接

# 内连接  select * from book inner join publish on book.publish_id=publish.id;
id   name   price   publish_id   id    name         addr
1    西游记   33      1           1     北京出版社    北京
2    红楼梦   56      1           1     北京出版社    北京
3    三国     66      2           2      南京出版社   南京

只展示两张表共有的数据

全连接

# 全连接(mysl不支持)
select * from book left join publish on book.publish_id=publish.id
union
select * from book right join publish on book.publish_id=publish.id;
id   name   price   publish_id   id    name         addr
1    西游记   33      1           1     北京出版社    北京
2    红楼梦   56      1           1     北京出版社    北京
3    三国     66      2           2      南京出版社   南京
4    西厢记   55      6           null     null      null
null  null   null     null	       3      东京出版社   东京   

使用union将左右连起来,全部展示出来,没有的就用null填充

笛卡尔积

笛卡尔积是将所有的数据全部展示出来,将一张表的数据每条都映射到另一张表上,这样的数据会重复,一般笛卡尔积后,过滤


id   name   price   publish_id   id    name         addr
1    西游记   33      1           1     北京出版社    北京
1    西游记   33      1           2      南京出版社   南京
1    西游记   33      1           3      东京出版社   东京 

2
2
2

3
3
3

4
4
4


select * from book,publish where book.publish_id=publish.id

缓存

在动态的网站中,用户所有的请求服务器都会去数据库中进行相应的增删改查,渲染模板,执行业务逻辑,最后生成用户看到的页面。当一个网站用户访问量很大的时候,每一次的后台操作,都会消耗很多的服务器资源,所以就需要使用缓存来减轻后端服务器的压力,缓存是将一些常用的数据保存在内存或者memcache中,在一定的时间内有人来访问这些数据时,则不再去执行数据库及渲染模板等操作,而是直接从内存或memcache的缓存中去取得数据然后返回给用户

1.全站缓存

默认就是缓存到内存中

from django.conf import global_setting
可以查看全局配置文件源码

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
    }
}

全站缓存,只需要配置中间件即可

缓存整个站点,是最简单的缓存方法

在 MIDDLEWARE_CLASSES 中加入 “update” 和 “fetch” 中间件
MIDDLEWARE_CLASSES = (
    ‘django.middleware.cache.UpdateCacheMiddleware’, #第一
    'django.middleware.common.CommonMiddleware',
    ‘django.middleware.cache.FetchFromCacheMiddleware’, #最后
)
“update” 必须配置在第一个
“fetch” 必须配置在最后一个
缓存到文件中

以上都是缓存到内存中,还可以缓存到文件中,只需一下配置即可

setting.py

CACHES = {
 'default': {
  'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', # 指定缓存使用的引擎
  'LOCATION': 'E:\django_cache',          # 指定缓存的路径
  'TIMEOUT': 300,              # 缓存超时时间(默认为300秒,None表示永不过期)
  'OPTIONS': {
   'MAX_ENTRIES': 300,            # 最大缓存记录的数量(默认300)
   'CULL_FREQUENCY': 3,           # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
  }
 }
}

然后再次刷新浏览器,可以看到在刚才配置的目录下生成的缓存文件

2.视图函数缓存

只需要在需要缓存的视图函数上加上装饰器

from django.views.decorators.cache import cache_page


@cache_page(timeout=10)  # 缓存超时时间10秒
def home(request):
    print('缓存中。。。')
    return render(request, 'home.html')

3.局部缓存

可以在模板中使用,添加一个标签

html

{% load cache %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
 <h3 style="color: green">不缓存:-----{{ t }}</h3>

{% cache 2 'name' %}
 <h3>缓存:-----:{{ t }}</h3>
{% endcache %}

</body>
</html>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
django mysqlclient是用于在Django项目中连接和操作MySQL数据库的Python库。它是django官方推荐的库之一。 在使用django mysqlclient之前,你需要先安装mysqlclient库,并在项目中配置数据库连接信息。 首先,你需要安装mysqlclient库,可以使用pip命令进行安装: ``` pip install mysqlclient ``` 然后,在Django项目的settings.py文件中配置数据库连接信息。你需要指定数据库引擎为'django.db.backends.mysql',数据库名称、用户名、密码、主机和端口等详细信息。这些信息可以根据你自己的环境进行配置。例如: ``` DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'test', 'USER': 'root', 'PASSWORD': 'hirain123', 'HOST': 'localhost', 'PORT': '3306', 'OPTIONS': { 'init_command': 'SET sql_model="STRICT_TRANS_TABLES"', } } } ``` 接下来,在子应用的models.py文件中定义模型类。你可以使用Django提供的字段类型来定义表的字段,并通过Meta类指定表名。例如,以下是一个User模型的示例: ``` from django.db import models class User(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=50) level = models.IntegerField(default=1) createTime = models.DateTimeField(null=True) class Meta: db_table = 'User' ``` 最后,在子应用中的admin.py文件中注册模型类,以便在Django的后台管理界面中对数据进行管理。 总结一下,要在Django项目中使用django mysqlclient,你需要先安装mysqlclient库,并在settings.py配置数据库连接信息。然后,在models.py中定义模型类,在admin.py中注册模型类。这样就可以通过Django的后台管理界面对MySQL数据库进行操作了。<span class="em">1</span><span class="em">2</span><span class="em">3</span>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值