python终极篇 --- django (01)
服务端与浏览器收发信息:
socket 套接字 是应用层和传输层之间一个虚拟层,是一个接口.
import socket sk = socket.socket() sk.bind(("127.0.0.1", 80)) sk.listen() while true: conn, addr = sk.accept() data = conn.recv(8096) conn.send(b"ok") conn.close()
打印一下收到的消息是什么>???
将\r\n替换成换行看得更清晰点: get / http/1.1 host: 127.0.0.1:8080 connection: keep-alive cache-control: max-age=0 upgrade-insecure-requests: 1 user-agent: mozilla/5.0 (windows nt 6.1; wow64) applewebkit/537.36 (khtml, like gecko) chrome/66.0.3355.4 safari/537.36 accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 accept-encoding: gzip, deflate, br accept-language: zh-cn,zh;q=0.9 cookie: csrftoken=cthepyarjoknx5onvwxiteojxpnyj29l4bw4506yovqfaiffahm0ewdzqkmw6jm8
那浏览器收到的消息是什么?
通过以上对比,发现收发消息的格式都是一样的---即为 http协议格式
每个http请求和响应都遵循相同的格式,一个http包含header和body两部分,其中body是可选的。
http响应的header中有一个 content-type
表明响应的内容格式。它的值如text/html; charset=utf-8。
text/html则表示是网页,charset=utf-8则表示编码为utf-8。
mport socket sock = socket.socket(socket.af_inet, socket.sock_stream) sock.bind(('127.0.0.1', 8000)) sock.listen() while true: conn, addr = sock.accept() data = conn.recv(8096) # 给回复的消息加上响应状态行 conn.send(b"http/1.1 200 ok\r\n\r\n") 不加这行代码返回不了数据 conn.send(b"ok") conn.close()
""" 根据url中不同的路径返回不同的内容 """ import socket sk = socket.socket() sk.bind(("127.0.0.1", 8080)) # 绑定ip和端口 sk.listen() # 监听 while true: # 等待连接 conn, add = sk.accept() data = conn.recv(8096) # 接收客户端发来的消息 # 从data中取到路径 data = str(data, encoding="utf8") # 把收到的字节类型的数据转换成字符串 # 按\r\n分割 data1 = data.split("\r\n")[0] url = data1.split()[1] # url是我们从浏览器发过来的消息中分离出的访问路径 conn.send(b'http/1.1 200 ok\r\n\r\n') # 因为要遵循http协议,所以回复的消息也要加状态行 # 根据不同的路径返回不同内容 if url == "/index/": response = b"index" elif url == "/home/": response = b"home" else: response = b"404 not found!" conn.send(response) conn.close()
""" 根据url中不同的路径返回不同的内容--函数版 """ import socket sk = socket.socket() sk.bind(("127.0.0.1", 8080)) # 绑定ip和端口 sk.listen() # 监听 # 将返回不同的内容部分封装成函数 def func(url): s = "这是{}页面!".format(url) return bytes(s, encoding="utf8") while true: # 等待连接 conn, add = sk.accept() data = conn.recv(8096) # 接收客户端发来的消息 # 从data中取到路径 data = str(data, encoding="utf8") # 把收到的字节类型的数据转换成字符串 # 按\r\n分割 data1 = data.split("\r\n")[0] url = data1.split()[1] # url是我们从浏览器发过来的消息中分离出的访问路径 conn.send(b'http/1.1 200 ok\r\n\r\n') # 因为要遵循http协议,所以回复的消息也要加状态行 # 根据不同的路径返回不同内容,response是具体的响应体 if url == "/index/": response = func(url) elif url == "/home/": response = func(url) else: response = b"404 not found!" conn.send(response) conn.close()
""" 根据url中不同的路径返回不同的内容--函数进阶版 """ import socket sk = socket.socket() sk.bind(("127.0.0.1", 8080)) # 绑定ip和端口 sk.listen() # 监听 # 将返回不同的内容部分封装成不同的函数 def index(url): s = "这是{}页面xx!".format(url) return bytes(s, encoding="utf8") def home(url): s = "这是{}页面。。!".format(url) return bytes(s, encoding="utf8") # 定义一个url和实际要执行的函数的对应关系 list1 = [ ("/index/", index), ("/home/", home), ] while true: # 等待连接 conn, add = sk.accept() data = conn.recv(8096) # 接收客户端发来的消息 # 从data中取到路径 data = str(data, encoding="utf8") # 把收到的字节类型的数据转换成字符串 # 按\r\n分割 data1 = data.split("\r\n")[0] url = data1.split()[1] # url是我们从浏览器发过来的消息中分离出的访问路径 conn.send(b'http/1.1 200 ok\r\n\r\n') # 因为要遵循http协议,所以回复的消息也要加状态行 # 根据不同的路径返回不同内容 func = none # 定义一个保存将要执行的函数名的变量 for item in list1: if item[0] == url: func = item[1] break if func: response = func(url) else: response = b"404 not found!" # 返回具体的响应消息 conn.send(response) conn.close()
""" 根据url中不同的路径返回不同的内容--函数进阶版 返回独立的html页面 """ import socket sk = socket.socket() sk.bind(("127.0.0.1", 8080)) # 绑定ip和端口 sk.listen() # 监听 # 将返回不同的内容部分封装成不同的函数 def index(url): # 读取index.html页面的内容 with open("index.html", "r", encoding="utf8") as f: s = f.read() # 返回字节数据 return bytes(s, encoding="utf8") def home(url): with open("home.html", "r", encoding="utf8") as f: s = f.read() return bytes(s, encoding="utf8") # 定义一个url和实际要执行的函数的对应关系 list1 = [ ("/index/", index), ("/home/", home), ] while true: # 等待连接 conn, add = sk.accept() data = conn.recv(8096) # 接收客户端发来的消息 # 从data中取到路径 data = str(data, encoding="utf8") # 把收到的字节类型的数据转换成字符串 # 按\r\n分割 data1 = data.split("\r\n")[0] url = data1.split()[1] # url是我们从浏览器发过来的消息中分离出的访问路径 conn.send(b'http/1.1 200 ok\r\n\r\n') # 因为要遵循http协议,所以回复的消息也要加状态行 # 根据不同的路径返回不同内容 func = none # 定义一个保存将要执行的函数名的变量 for item in list1: if item[0] == url: func = item[1] break if func: response = func(url) else: response = b"404 not found!" # 返回具体的响应消息 conn.send(response) conn.close()
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="x-ua-compatible" content="ie=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>index</title> </head> <body> <div>这是index页面</div> </body> </html>
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="x-ua-compatible" content="ie=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>index</title> </head> <body> <div>这是home页面</div> </body> </html>
""" 根据url中不同的路径返回不同的内容--函数进阶版 返回独立的html页面 """ import socket sk = socket.socket() sk.bind(("127.0.0.1", 8080)) # 绑定ip和端口 sk.listen() # 监听 # 将返回不同的内容部分封装成不同的函数 def index(url): # 读取index.html页面的内容 with open("index.html", "r", encoding="utf8") as f: s = f.read() # 返回字节数据 return bytes(s, encoding="utf8") def home(url): with open("home.html", "r", encoding="utf8") as f: s = f.read() return bytes(s, encoding="utf8") def timer(url): import time with open("time.html", "r", encoding="utf8") as f: s = f.read() s = s.replace('@@time@@', time.strftime("%y-%m-%d %h:%m:%s")) return bytes(s, encoding="utf8") # 定义一个url和实际要执行的函数的对应关系 list1 = [ ("/index/", index), ("/home/", home), ("/time/", timer), ] while true: # 等待连接 conn, add = sk.accept() data = conn.recv(8096) # 接收客户端发来的消息 # 从data中取到路径 data = str(data, encoding="utf8") # 把收到的字节类型的数据转换成字符串 # 按\r\n分割 data1 = data.split("\r\n")[0] url = data1.split()[1] # url是我们从浏览器发过来的消息中分离出的访问路径 conn.send(b'http/1.1 200 ok\r\n\r\n') # 因为要遵循http协议,所以回复的消息也要加状态行 # 根据不同的路径返回不同内容 func = none # 定义一个保存将要执行的函数名的变量 for item in list1: if item[0] == url: func = item[1] break if func: response = func(url) else: response = b"404 not found!" # 返回具体的响应消息 conn.send(response) conn.close()
以下内容目前随便看看就行了,反正我没看懂
============>>>>>>...服务器程序和应用程序<<<<<<<<<=================
对于真实开发中的python web程序来说,一般会分为两部分:服务器程序和应用程序。
服务器程序负责对socket服务端进行封装,并在请求到来时,对请求的各种数据进行整理。
应用程序则负责具体的逻辑处理。为了方便应用程序的开发,就出现了众多的web框架,例如:django、flask、web.py 等。不同的框架有不同的开发方式,但是无论如何,开发出的应用程序都要和服务器程序配合,才能为用户提供服务。
这样,服务器程序就需要为不同的框架提供不同的支持。这样混乱的局面无论对于服务器还是框架,都是不好的。对服务器来说,需要支持各种不同框架,对框架来说,只有支持它的服务器才能被开发出的应用使用。
这时候,标准化就变得尤为重要。我们可以设立一个标准,只要服务器程序支持这个标准,框架也支持这个标准,那么他们就可以配合使用。一旦标准确定,双方各自实现。这样,服务器可以支持更多支持标准的框架,框架也可以使用更多支持标准的服务器。
wsgi(web server gateway interface)就是一种规范,它定义了使用python编写的web应用程序与web服务器程序之间的接口格式,实现web应用程序与web服务器程序间的解耦。
常用的wsgi服务器有uwsgi、gunicorn。而python标准库提供的独立wsgi服务器叫wsgiref,django开发环境用的就是这个模块来做服务器。
wsgiref
我们利用wsgiref模块来替换我们自己写的web框架的socket server部分:
- """
- 根据url中不同的路径返回不同的内容--函数进阶版
- 返回html页面
- 让网页动态起来
- wsgiref模块版
- """
- from wsgiref.simple_server import make_server
- # 将返回不同的内容部分封装成函数
- def index(url):
- # 读取index.html页面的内容
- with open("index.html", "r", encoding="utf8") as f:
- s = f.read()
- # 返回字节数据
- return bytes(s, encoding="utf8")
- def home(url):
- with open("home.html", "r", encoding="utf8") as f:
- s = f.read()
- return bytes(s, encoding="utf8")
- def timer(url):
- import time
- with open("time.html", "r", encoding="utf8") as f:
- s = f.read()
- s = s.replace('@@time@@', time.strftime("%y-%m-%d %h:%m:%s"))
- return bytes(s, encoding="utf8")
- # 定义一个url和实际要执行的函数的对应关系
- list1 = [
- ("/index/", index),
- ("/home/", home),
- ("/time/", timer),
- ]
- def run_server(environ, start_response):
- start_response('200 ok', [('content-type', 'text/html;charset=utf8'), ]) # 设置http响应的状态码和头信息
- url = environ['path_info'] # 取到用户输入的url
- func = none
- for i in list1:
- if i[0] == url:
- func = i[1]
- break
- if func:
- response = func(url)
- else:
- response = b"404 not found!"
- return [response, ]
- if __name__ == '__main__':
- httpd = make_server('127.0.0.1', 8090, run_server)
- print("我在8090等你哦...")
- httpd.serve_forever()
jinja2
上面的代码实现了一个简单的动态,我完全可以从数据库中查询数据,然后去替换我html中的对应内容,然后再发送给浏览器完成渲染。 这个过程就相当于html模板渲染数据。 本质上就是html内容中利用一些特殊的符号来替换要展示的数据。 我这里用的特殊符号是我定义的,其实模板渲染有个现成的工具: jinja2
下载jinja2:
pip install jinja2
<!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"> <title>title</title> </head> <body> <h1>姓名:{{name}}</h1> <h1>爱好:</h1> <ul> {% for hobby in hobby_list %} <li>{{hobby}}</li> {% endfor %} </ul> </body> </html>
使用jinja2渲染index2.html文件:
- from wsgiref.simple_server import make_server
- from jinja2 import template
- def index(url):
- # 读取html文件内容
- with open("index2.html", "r", encoding="utf8") as f:
- data = f.read()
- template = template(data) # 生成模板文件
- ret = template.render({'name': 'alex', 'hobby_list': ['抽烟', '喝酒', '烫头']}) # 把数据填充到模板中
- return bytes(ret, encoding="utf8")
- def home(url):
- with open("home.html", "r", encoding="utf8") as f:
- s = f.read()
- return bytes(s, encoding="utf8")
- # 定义一个url和实际要执行的函数的对应关系
- list1 = [
- ("/index/", index),
- ("/home/", home),
- ]
- def run_server(environ, start_response):
- start_response('200 ok', [('content-type', 'text/html;charset=utf8'), ]) # 设置http响应的状态码和头信息
- url = environ['path_info'] # 取到用户输入的url
- func = none
- for i in list1:
- if i[0] == url:
- func = i[1]
- break
- if func:
- response = func(url)
- else:
- response = b"404 not found!"
- return [response, ]
- if __name__ == '__main__':
- httpd = make_server('127.0.0.1', 8090, run_server)
- print("我在8090等你哦...")
- httpd.serve_forever()
现在的数据是我们自己手写的,那可不可以从数据库中查询数据,来填充页面呢?
使用pymysql连接数据库:
conn = pymysql.connect(host="127.0.0.1", port=3306, user="root", passwd="xxx", db="xxx", charset="utf8") cursor = conn.cursor(cursor=pymysql.cursors.dictcursor) cursor.execute("select name, age, department_id from userinfo") user_list = cursor.fetchall() cursor.close() conn.close()
创建一个测试的user表:
create table user( id int auto_increment primary key, name char(10) not null, hobby char(20) not null )engine=innodb default charset=utf8;
模板的原理就是字符串替换,我们只要在html页面中遵循jinja2的语法规则写上,其内部就会按照指定的语法进行相应的替换,从而达到动态的返回内容。
以下内容留存,一些配置信息修改: 重要
模板文件配置:
templates = [ { 'backend': 'django.template.backends.django.djangotemplates', 'dirs': [os.path.join(base_dir, "template")], # template文件夹位置 'app_dirs': true, 'options': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ]
静态文件配置:
static_url = '/static/' # html中使用的静态文件夹前缀 staticfiles_dirs = [ os.path.join(base_dir, "static"), # 静态文件存放位置 ]
刚开始学习时可在配置文件中暂时禁用csrf中间件,方便表单提交测试。
middleware = [ 'django.middleware.security.securitymiddleware', 'django.contrib.sessions.middleware.sessionmiddleware', 'django.middleware.common.commonmiddleware', # 'django.middleware.csrf.csrfviewmiddleware', 'django.contrib.auth.middleware.authenticationmiddleware', 'django.contrib.messages.middleware.messagemiddleware', 'django.middleware.clickjacking.xframeoptionsmiddleware', ]
1. http协议
1. 请求(浏览器发送给服务器的消息-request)
格式:
请求方式 url 协议版本
k1: v1
k2: v2
请求数据(请求体)
2. 响应(服务器返回给浏览器的消息-response)
格式:
协议版本 状态码 状态描述符
k1: v1
k2: v2
响应体(html)
2. web框架
本质: socket服务端
功能:
a. socket收发消息
b. url和函数的对应关系,根据不同的url执行不同的函数,返回函数的结果
c. 读取html文件,进行了一个字符替换(模板渲染)
分类:
django flask tornado
完成了a,b,c三个功能的 ——》 tornado
完成了b,c 两个功能 ——》 django
完成了b 一个功能 ——》 flask
另一种分类:
1. django 大而全
2. 其他 短小精悍
3. 安装django
1. pycharm
file settings project 点加号 输入django 选择版本 下载
2. 命令行
pip install django==1.11.15
4. 创建django项目
1. 命令行
django-admin startproject 项目名
2. pycharm
file ——》 new project ——》 django ——》 项目名 ——》选择解释器 ——》create
5. 启动django项目
1. 命令行
切换到有manage.py的目录下
python manage.py runserver # 127.0.0.1:8000
python manage.py runserver 80 # 127.0.0.1:80
python manage.py runserver 0.0.0.0:80 # 0.0.0.0:80
2. pycharm
配置好 点绿色三角
6. 配置
静态文件
static_url = '/static/' # 别名
staticfiles_dirs = [
os.path.join(base_dir, 'static')
]
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1,form表单提交数据注意事项:
1. input 标签有name属性
2. action="" method="post" 提交的地方 提交的方式
3. 有一个input的type="submit" 或者有一个button按钮
4.注意form标签的位置,提交按钮和输入框一定要在同一个form表单下
2. get 和 post 的区别
1. get
1. 获取一个页面
2. 提交数据 数据显示在url ?user=alex&pwd=alexdsb
2. post
form表单提交数据 数据不显示
3. 使用mysql数据库的配置
1. databases = {
'default': {
'engine': 'django.db.backends.mysql', # 引擎
'name': 'day66', # 数据库名
'user':'root', # 用户名
'password':'', # 密码
'host':'127.0.0.1', # ip
'port': 3306, # 端口号
}
}
2. 在与settings.py同级目录下的__init__.py文件中写:
import pymysql
pymysql.install_as_mysqldb()
3. 创建表:
在models.py中写类
class userinfo(models.model):
user = models.charfield(max_length=32) # varchar(32)
pwd = models.charfield(max_length=32)
4. 执行两条命令:
python manage.py makemigrations # 把models.py的变化记录下来
python manage.py migrate # 去修改你的数据库
4. orm操作:
from login import models
1. 获取数据表所有内容
all = models.userinfo.objects.all()
2. 获取一条数据
models.userinfo.objects.get(user='alex')
# 没有数据或者多条数据就报错
3. 向数据库插入一条数据
models.userinfo.objects.create(user='alex',pwd='alexdsb')
补充: redirect(地址) 跳转到某地址, 若地址是文件,前边不用加 /,若是函数,必须加 /
创建app,必须在配置文件settings中的 installed_apps 中加入app名称
from django.shortcuts import httpresponse,render,redirect
def login(request): if request.method == "post": age = request.post.get("age") user = request.post.get("userame") pwd = request.post.get("password") if age == none: all = models.userinfo2.objects.all() for i in all: if i.user == user and i.pwd == pwd: print("nihao a ") return redirect("/weixin/") return render(request, "login.html") else: models.userinfo2.objects.create(user=user, pwd=pwd, age=age) return render(request, "login.html")