python django基础一web框架的本质
web框架的本质就是一个socket服务端,而浏览器就是一个socker客户端,基于请求做出相应,客户端先请求,服务器做出对应响应
按照http协议的请求发送,服务器按照http协议来相应,这样的通信就可以自己实现web框架了
简单web框架
import socket server = socket.socket() server.bind(('127.0.0.1', 8080)) # 把地址绑到套接字 server.listen() # 监听链接 while 1: conn, addr = server.accept() # 接受客户端连接 from_b_msg = conn.recv(1024).decode('utf-8') # 接收客户端信息 print(from_b_msg) path = from_b_msg.split('\r\n')[0].split()[1] # 赛选到客户端的第一行信息 conn.send(b'HTTP/1.1 200 ok\r\n\r\n') # http响应格式 1.状态行 回车符 换行符 2.相应头部头部字段:值 回车符 换行符 回车符 换行符响应正文 # conn.send(b'hello') if path == '/': # 只写这一个 你会发现 该 网页css js 应用都没应用上 因为他们 请求/test.css /timg.jpg with open('test.html', 'rb') as f: data = f.read() conn.send(data) conn.close() elif path == '/test.css': with open('test.css', 'rb') as f: data = f.read() conn.send(data) conn.close() elif path == '/timg.jpg': with open('timg.jpg', 'rb') as f: data = f.read() conn.send(data) conn.close() elif path == '/test.js': with open('test.js', 'rb') as f: data = f.read() conn.send(data) conn.close() elif path == '/meinv.ico': with open('meinv.ico', 'rb') as f: data = f.read() conn.send(data) conn.close()
test.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! --> <title>Bootstrap 101 Template</title> <link rel="stylesheet" href="test.css"> <link rel="icon" href="meinv.ico"> <!-- Bootstrap --> <!--<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">--> <style> </style> </head> <body> <h1>来首诗,菩提本无树,明镜亦非台</h1> <!--<img src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1550637152712&di=1caeff14731881d6d2ad4d9681ad031a&imgtype=0&src=http%3A%2F%2Fimgsrc.baidu.com%2Fimgad%2Fpic%2Fitem%2F0b55b319ebc4b7454d716709c5fc1e178b8215c3.jpg" alt="">--> <img src="timg.jpg" alt=""> <!--<script src="jquery.js"></script>--> <!--<script src="bootstrap/js/bootstrap.min.js"></script>--> <!--<script>--> <!--alert('xxx');--> <!--</script>--> <script src="test.js"></script> </body> </html>
test.css
h1{ background-color: green; } img{ width: 200px; height: 200px; }
test.js
alert('xxx');
这2个图片 我就不提供了
timg.jpg
meinv.ico
超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)
HTTP是一个客户端终端(用户)和服务器端(网站)请求和应答的标准(TCP)。
工作原理
1.客户端到连接服务器
一个HTTP客户端,通常是浏览器,与Web服务器的HTTP端口(默认为80)建立一个TCP套接字连接:如http://www.baidu.com
2.发送http请求
通过TCP套接字,客户端向Web服务器发送一个文本的请求报文,一个请求报文由请求行、请求头部、空行和请求数据4部分组成。
URL包含:/index/index2?a=1&b=2;路径和参数都在这里。
3.服务接收请求并返回http响应
Web服务器解析请求,定位请求资源。服务器将资源复本写到TCP套接字,由客户端读取。一个响应由状态行、响应头部、空行和响应数据4部分组成。
4.释放连接tcp连接
若connection 模式为close,则服务器主动关闭TCP连接,客户端被动关闭连接,释放TCP连接;若connection 模式为keepalive,则该连接会保持一段时间,在该时间内可以继续接收请求;
5.客户端浏览器解析HTML内容
客户端浏览器首先解析状态行,查看表明请求是否成功的状态代码。然后解析每一个响应头,响应头告知以下为若干字节的HTML文档和文档的字符集。客户端浏览器读取响应数据HTML,根据HTML的语法对其进行格式化,并在浏览器窗口中显示。
只加根判断应答会出现 下面情况
请求方式: get与post请求(通过form表单我们自己写写看)
-
GET提交的数据会放在URL之后,也就是请求行里面,以?分割URL和传输数据,参数之间以&相连,如EditBook?name=test1&id=123456.(请求头里面那个content-type做的这种参数形式,后面讲) POST方法是把提交的数据放在HTTP包的请求体中.
-
GET提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制.
-
GET与POST请求在服务端获取请求数据方式不同,就是我们自己在服务端取请求数据的时候的方式不同了,这句废话昂。
http状态码
- 1xx消息——请求已被服务器接收,继续处理
- 2xx成功——请求已成功被服务器接收、理解、并接受
- 3xx重定向——需要后续操作才能完成这一请求
- 4xx请求错误——请求含有词法错误或者无法被执行
- 5xx服务器错误——服务器在处理某个正确请求时发生错误
高级点的 web框架
from threading import Thread import socket server = socket.socket() server.bind(('127.0.0.1', 8080)) server.listen() def html(conn): with open('test.html', 'rb') as f: data = f.read() conn.send(data) conn.close() def js(conn): with open('test.js', 'rb') as f: data = f.read() conn.send(data) conn.close() def css(conn): with open('test.css', 'rb') as f: data = f.read() conn.send(data) conn.close() def img(conn): with open('timg.jpg', 'rb') as f: data = f.read() conn.send(data) conn.close() def ico(conn): with open('meinv.ico', 'rb') as f: data = f.read() conn.send(data) conn.close() url = [ ('/', html), ('/test.css', css), ('/timg.jpg', img), ('/test.js', js), ('/meinv.ico', ico), ] while 1: conn, addr = server.accept() from_b_msg = conn.recv(1024).decode('utf-8') path = from_b_msg.split('\r\n')[0].split(' ')[1] conn.send(b'HTTP/1.1 200 ok\r\nk1:v1\r\n\r\n') for i in url: if i[0] == path: t=Thread(target=i[1],args=(conn,)) t.start()
根据不同路径返回不同页面 web框架 返回动态页面web框架
from threading import Thread import socket server = socket.socket() # server.bind(('192.168.12.45',8080)) server.bind(('127.0.0.1',8080)) server.listen() import datetime def base(conn): with open('base.html','r',encoding='utf-8') as f: data = f.read() t1 = datetime.datetime.now() new_data = data.replace('@xx@',str(t1)) conn.send(new_data.encode('utf-8')) #conn是形参 是发送消息conn 管道 def index(conn): with open('index.html', 'rb') as f: data = f.read() conn.send(data) def home(conn): with open('home.html', 'rb') as f: data = f.read() conn.send(data) def articles(conn): with open('art.html', 'rb') as f: data = f.read() conn.send(data) urlpatterns=[ ('/',base), ('/index',index), ('/home',home), ('/articles',articles), ] while 1: conn, addr = server.accept() from_b_msg = conn.recv(1024).decode('utf-8') print(from_b_msg) path = from_b_msg.split('\r\n')[0].split(' ')[1] # print(path) conn.send(b'HTTP/1.1 200 ok\r\nk1:v1\r\n\r\n') # conn.send(b'<h1>hello</h1>') for url_func in urlpatterns: if url_func[0] == path: #多线程函数版 #注意这传参是实参 t = Thread(target=url_func[1],args=(conn,)) t.start() # 简单函数版 # url_func[1](conn)
base.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! --> <title>Bootstrap 101 Template</title> <!-- Bootstrap --> <!--<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">--> </head> <body> <h1 style="color: purple;">欢迎来到王者荣耀页面</h1> <a href="http://127.0.0.1:8080/index">这是index</a> <a href="http://127.0.0.1:8080/home">这是home</a> <h1 style="color: pink;">@xx@</h1> <!--<script src="jquery.js"></script>--> <!--<script src="bootstrap/js/bootstrap.min.js"></script>--> </body> </html>
index.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! --> <title>Bootstrap 101 Template</title> <!-- Bootstrap --> <!--<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">--> </head> <body> <div>这是index页面</div> <!--<script src="jquery.js"></script>--> <!--<script src="bootstrap/js/bootstrap.min.js"></script>--> </body> </html>
home.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! --> <title>Bootstrap 101 Template</title> <!-- Bootstrap --> <!--<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">--> </head> <body> <h1>这是home页面</h1> <!--<script src="jquery.js"></script>--> <!--<script src="bootstrap/js/bootstrap.min.js"></script>--> </body> </html>
form表单提交
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="http://127.0.0.1:8080" method=""> 用户名:<input type="text" name="username"> 密码:<input type="password" name="password"> <input type="submit"></input> </form> </body> </html>
server 得到数据
GET /?username=zaizai&password=123 HTTP/1.1 Host: 127.0.0.1:8080 Connection: keep-alive Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36
爬虫模拟user-agent
import requests
# res = requests.get('https://www.jd.com')
res = requests.get('https://dig.chouti.com/',headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36',
})
# print(res.text)
with open('ct.html','w',encoding='utf-8') as f:
f.write(res.text)
wsgire模块
from wsgiref.simple_server import make_server # wsgiref本身就是个web框架,提供了一些固定的功能(请求和响应信息的封装,不需要我们自己写原生的socket了也不需要咱们自己来完成请求信息的提取了,提取起来很方便) #函数名字随便起 def application(environ, start_response): ''' :param environ: 是全部加工好的请求信息,加工成了一个字典,通过字典取值的方式就能拿到很多你想要拿到的信息 :param start_response: 帮你封装响应信息的(响应行和响应头),注意下面的参数 :return: ''' start_response('200 OK', [('Content-Type', 'text/html'),('k1','v1')]) # print(environ) print('>>>>>',environ['PATH_INFO']) #输入地址127.0.0.1:8000,这个打印的是'/',输入的是127.0.0.1:8000/index,打印结果是'/index' return [b'<h1>Hello, web!</h1>'] #和咱们学的socketserver那个模块很像啊 httpd = make_server('127.0.0.1', 8080, application) print('Serving HTTP on port 8080...') # 开始监听HTTP请求: httpd.serve_forever()
基于wsgire模块 起飞版框架
先看一下分析图
manage.py
from urls import url_patterns from wsgiref.simple_server import make_server # 框架主逻辑代码 def application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html'), ('k1', 'v1')]) path = environ['PATH_INFO'] # 所有的请求 取到其中的 print('path>>>', path) data = b'page not found ,404!!!'#没有走404 for path_func in url_patterns: if path == path_func[0]: data = path_func[1](environ) print(data) return [data] httpd = make_server('127.0.0.1', 8080, application) print('Serving HTTP on port 8080...') httpd.serve_forever()
ruls文件
import views # 路径与函数的对应关系 url_patterns = [ ('/', views.base), ('/login',views.login), ('/auth',views.auth) ]
views文件
import pymysql from urllib.parse import parse_qs # 首页处理函数 def base(environ): with open('templates/base.html', 'rb') as f: data = f.read() return data def login(environ): with open('templates/login.html', 'rb') as f: data = f.read() return data user = None def auth(environ): args = parse_qs(environ['QUERY_STRING']) # 可把用户请求转化成字典 username = args['username'][0] password = args['password'][0] # print('>>>>>',parse_qs(args)) #{'a': ['1'], 'b': ['2']} conn = pymysql.connect( host='127.0.0.1', port=3306, user='root', password='123456.com', database='auth', charset='utf8' ) cursor = conn.cursor() sql = 'select * from userinfo where name=%s and password=%s;' res = cursor.execute(sql, [username, password]) if res: global user user = username with open('templates/base.html', 'rb') as f: data = f.read() else: data = '密码错误'.encode('gbk') return data
models文件
# 通过pymysql来创建表 import pymysql conn = pymysql.connect( host='127.0.0.1', port=3306, user='root', password='123456.com', database='auth', charset='utf8' ) cursor = conn.cursor(pymysql.cursors.DictCursor) sql = """ # create table userinfo( # id int primary key auto_increment, # name char(20) not null unique, # password char(20) not null # # ); insert into userinfo(name,password) values('alex','123'),('alexsb','123'); """ cursor.execute(sql) conn.commit() conn.close()
templates文件夹 下面存放html文件
base.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>欢迎</h1> </body> </html>
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="http://127.0.0.1:8080/auth"> <label for="username">用户名</label> <input type="text" id="username" name="username"> <label for="password">密码</label> <input id="password" type="password" name="password"> <input type="submit"> </form> </body> </html>
MVT和MTV的差别
将来要说的MVC框架是什么呢:
M:model.py 就是和数据库打交道用的,创建表等操作
V:View 视图(视图函数,html文件)
C:controller 控制器(其实就是我百度云代码里面那个urls文件里面的内容,url(路径)分发与视图函数的逻辑处理)
Django叫做MTV框架
M:model.py 就是和数据库打交道用的,创建表等操作(和上面一样)
T:templates 存放HTML文件的
V:View 视图函数(逻辑处理)
其实你会发现MTV比MVC少一个url分发的部分
所以我们学的django还要学一个叫做url控制器(路径分发)的东西,MTV+url控制器就是我们django要学的内容。
模版渲染jinja2
实现了一个简单的动态页面(字符串替换)
import socket from threading import Thread from jinja2 import Template import datetime server = socket.socket() server.bind(('127.0.0.1', 8080)) server.listen() def base(conn): # with open('base.html','r',encoding='utf-8') as f: # data = f.read() # t1 = datetime.datetime.now() # new_data = data.replace('@xx@',str(t1)) # conn.send(new_data.encode('utf-8')) with open('jinja2page.html', 'r', encoding='utf-8') as f: data = f.read() t = Template(data) new_data = t.render({"name": "于谦", "hobby_list": ["烫头", "泡吧"]}) # return conn.send(new_data.encode('utf-8')) urlpatterns = [ ('/', base), ] while 1: conn, addr = server.accept() from_b_msg = conn.recv(1024).decode('utf-8') path = from_b_msg.split('\r\n')[0].split(' ')[1] # print(path) conn.send(b'HTTP/1.1 200 ok\r\nk1:v1\r\n\r\n') # conn.send(b'<h1>hello</h1>') for url_func in urlpatterns: if url_func[0] == path: # 多线程函数版 t = Thread(target=url_func[1], args=(conn,)) t.start() # 简单函数版 # url_func[1](conn)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>姓名:{{name}}</h1> <ul> {% for hobby in hobby_list %} <li>{{hobby}}</li> {% endfor%} </ul> </body> </html>
Django下载安装
pip3 install django==1.11.9
django-admin startproject mysite 创建了一个名为"mysite"的Django 项目:
python manage.py runserver 127.0.0.1:8080 #此时已经可以启动django项目
django-admin startapp app02 或者使用python manage.py startapp blog #通过执行manage.py文件来创建应用
python manage.py runserver 8080 #本机就不用写ip地址了 如果连端口都没写,默认是本机的8000端口
http://127.0.0.1:8080/时就可以看到
pycharm 创建方法
django 简单使用方法
目录结构
mysite 目录结构 manage.py mysqite settings.py 项目全局的配置信息 urls.py 路径和函数对应关系 wsgi.py socket相关的 app01 views.py 视图函数 就是业务逻辑代码 models.py 数剧库相关 templates 存放html文件的 django settings 配置文件里面关于这个文件夹的配置 'DIRS':[os.path.join(BASE_DIR,'templates')]
urls改变如下
from blog import views #引入views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index), url(r'^login/', views.login), url(r'^home/', views.home) ]
tempalates 下添加需要的html
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>{{ t }}</h1> </body> </html>
login.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! --> <title>Bootstrap 101 Template</title> </head> <body> <form action="http://127.0.0.1:8000/login/" method="get"> <label for="username">用户名</label><input id="username" type="text" name="username"> <label for="password">密码</label><input id="password" type="password" name="password"> <input type="submit"> </form> </body> </html>
在应用app下 添加需要的应用信息
from django.shortcuts import render,HttpResponse import datetime # Create your views here. def index(request): newdata = str(datetime.datetime.now()) return render(request, 'index.html', {'t': newdata}) def home(request): return render(request,'login.html') def login(request): #获取用户的请求方法 method = request.method if method == 'GET': # #返回页面 # return render(request,'login.html') # # else: #post方法获取数据,都是字符串类型 # uname = request.POST.get('username') #get方法获取数据,都是字符串类型 uname = request.GET.get('username') pwd = request.GET.get('password') print(uname,pwd) #alex 123 if uname == 'sb' and pwd == '222': #返回消息,写字符串就行 return HttpResponse('登录成功') else: return HttpResponse('验证失败')
进行登陆验证
失败后 会返回登陆失败 成功后返回成功
index 是一个动态的jianjia2 相应页面