01-Django初识
一、知识回顾
1、python基础
2、网络编程
3、并发编程
4、前端
5、数据库(MySQL)
二、今日概要
1、Web框架的本质
2、Django简介及安装使用
三、今日详细
1、Web应用
Web应用程序是一种可以通过Web访问的应用程序,程序的最大好处是用户很容易访问应用程序,用户只需要有浏览器即可,不需要再安装其他软件。
应用程序有两种模式C/S、B/S:
- C/S(Client/Server)是客户端/服务器端程序,也就是说这类程序一般独立运行。
- B/S(Browser/Server)就是浏览器端/服务器端应用程序,这类应用程序一般借助谷歌,火狐等浏览器来运行。
Web应用程序一般是B/S模式。Web应用程序首先是“应用程序”,和用什么程序语言(如:java,python等)编写出来的程序没有什么本质上的不同。在网络编程的意义下,浏览器是一个socket客户端,服务器是一个socket服务端。
import socket # 创建socket对象 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 绑定IP和端口 sock.bind(("127.0.0.1", 8888)) # 监听 sock.listen(5) while True: conn, addr = sock.accept() # 等待连接 data = conn.recv(1024) # 接收数据 print("请求信息====> %s" % data) # 发送数据 conn.send("HTTP/1.1 200 OK\r\nContent-Type: text/html;charset=utf-8\r\n\r\n".encode('utf-8')) conn.send("<h1>Welcome to 路飞学城</h1>".encode("utf-8")) conn.close()
2、Http协议简介
HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。
HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。
具体的内容请移步查看详情:点我啊!
补充内容:对URL的认识
URL是统一资源定位符,对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。
URL的组成部分(如:http://www.luffycity.com/home):
a、协议部分:在Internet中可以使用多种协议,如HTTP,FTP等等。上面的例子中“http”就是在声明协议,在"http"后面的“//”为分隔符。
b、域名部分:上面的例子URL的域名部分为“www.luffycity.com”。一个URL中,也可以使用IP地址作为域名使用(域名通过dns解析,最终访问的还是IP地址)。
c、端口部分:紧跟域名后面的就是端口,域名和端口之间使用“:”作为分隔符。端口不是一个URL必须的部分,如果省略端口部分,将采用默认端口(80)。
d、路径部分:以“/”字符区别路径中的每一个目录名称(如:http://www.luffycity.com/home,中的home就是路径名称)。
e、文件名部分:从域名后的最后一个“/”开始到“?”为止,是文件名部分,如果没有“?”,则是从域名后的最后一个“/”开始到“#”为止,是文件部分,如果没有“?”和“#”,那么从域名后的最后一个“/”开始到结束,都是文件名部分(如:https://hcdn1.luffycity.com/static/frontend/index/Luffy-study-logo.png)。本例中的文件名是“Luffy-study-logo.png”。文件名部分也不是一个URL必须的部分,如果省略该部分,则使用默认的文件名。
f、锚部分:从“#”开始到最后,都是锚部分。锚部分也不是一个URL必须的部分。我们一起学猫叫
g、参数部分:从“?”开始到“#”为止之间的部分为参数部分,又称搜索部分、查询部分。参数可以允许有多个参数,参数与参数之间用“&”作为分隔符。
3、根据不同路径返回不同内容
import socket # 创建socket对象 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 绑定IP和端口 sock.bind(("127.0.0.1", 8888)) # 监听 sock.listen(5) while True: conn, addr = sock.accept() # 等待连接 data = conn.recv(1024) # 接收数据 data = data.decode("utf-8") data_list = data.split() url = data_list[1] if data_list else None print("请求信息====> %s" % url) # 发送数据 conn.send("HTTP/1.1 200 OK\r\nContent-Type: text/html;charset=utf-8\r\n\r\n".encode('utf-8')) if url == "/index": conn.send("<h1>Welcome to 路飞学城</h1>".encode("utf-8")) elif url == "/japan": conn.send("<h2>---日韩专区---</h2>".encode("utf-8")) elif url == "/american": conn.send("<h2>---欧美专区---</h2>".encode("utf-8")) else: conn.send("<h2 style='color:red'>404 not found !</h2>".encode("utf-8")) conn.close()
4、根据不同路径返回不同内容(函数版)
import socket # 创建socket对象 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 绑定IP和端口 sock.bind(("127.0.0.1", 8888)) # 监听 sock.listen(5) def index(url): ret = "<h1>Welcome to 路飞学城 url ===> {}</h1>".format(url) return ret.encode("utf-8") def american(url): ret = "<h2>---欧美专区--- url ===> {}</h2>".format(url) return ret.encode("utf-8") def japan(url): ret = "<h2>---日韩专区--- url ===> {}</h2>".format(url) return ret.encode("utf-8") while True: conn, addr = sock.accept() # 等待连接 data = conn.recv(1024) # 接收数据 data = data.decode("utf-8") data_list = data.split() url = data_list[1] if data_list else None print("请求信息====> %s" % url) # 发送数据 conn.send("HTTP/1.1 200 OK\r\nContent-Type: text/html;charset=utf-8\r\n\r\n".encode('utf-8')) if url == "/index": ret = index(url) elif url == "/japan": ret = japan(url) elif url == "/american": ret = american(url) else: ret = "<h2 style='color:red'>404 not found !</h2>".encode("utf-8") conn.send(ret) conn.close()
5、根据不同路径返回不同内容(函数进阶版)
import socket # 创建socket对象 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 绑定IP和端口 sock.bind(("127.0.0.1", 8888)) # 监听 sock.listen(5) def index(url): ret = "<h1>Welcome to 路飞学城 url ===> {}</h1>".format(url) return ret.encode("utf-8") def american(url): ret = "<h2>---欧美专区--- url ===> {}</h2>".format(url) return ret.encode("utf-8") def japan(url): ret = "<h2>---日韩专区--- url ===> {}</h2>".format(url) return ret.encode("utf-8") url_list = [ ("/index", index), ("/american", american), ("/japan", japan), ] while True: conn, addr = sock.accept() # 等待连接 data = conn.recv(1024) # 接收数据 data = data.decode("utf-8") data_list = data.split() url = data_list[1] if data_list else None print("请求信息====> %s" % url) # 发送数据 conn.send("HTTP/1.1 200 OK\r\nContent-Type: text/html;charset=utf-8\r\n\r\n".encode('utf-8')) func = None for i in url_list: if url == i[0]: func = i[1] break if func: ret = func(url) else: ret = "<h2 style='color:red'>404 not found !</h2>".encode("utf-8") conn.send(ret) conn.close()
6、返回一个HTML文件内容
<!--index.html文件内容--> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <h1>Welcome to 路飞学城首页</h1> </body> </html>
import socket # 创建socket对象 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 绑定IP和端口 sock.bind(("127.0.0.1", 8888)) # 监听 sock.listen(5) def index(url): with open("index.html", "rb") as f: ret = f.read() return ret def american(url): ret = "<h2>---欧美专区--- url ===> {}</h2>".format(url) return ret.encode("utf-8") def japan(url): ret = "<h2>---日韩专区--- url ===> {}</h2>".format(url) return ret.encode("utf-8") url_list = [ ("/index", index), ("/american", american), ("/japan", japan), ] while True: conn, addr = sock.accept() # 等待连接 data = conn.recv(1024) # 接收数据 data = data.decode("utf-8") data_list = data.split() url = data_list[1] if data_list else None print("请求信息====> %s" % url) # 发送数据 conn.send("HTTP/1.1 200 OK\r\nContent-Type: text/html;charset=utf-8\r\n\r\n".encode('utf-8')) func = None for i in url_list: if url == i[0]: func = i[1] break if func: ret = func(url) else: ret = "<h2 style='color:red'>404 not found !</h2>".encode("utf-8") conn.send(ret) conn.close()
7、返回一个动态HTML文件内容
<!--timer.html文件内容--> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <!--此处使用“@@time@@”作为占位符--> <h2>bobo为您报时,现在是北京时间:@@time@@</h2> </body> </html>
import socket import time # 创建socket对象 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 绑定IP和端口 sock.bind(("127.0.0.1", 8888)) # 监听 sock.listen(5) def index(url): with open("timer.html", "rb") as f: ret = f.read() return ret def american(url): ret = "<h2>---欧美专区--- url ===> {}</h2>".format(url) return ret.encode("utf-8") def japan(url): ret = "<h2>---日韩专区--- url ===> {}</h2>".format(url) return ret.encode("utf-8") def timer(url): with open("timer.html", "r", encoding="utf-8") as f: data = f.read() now_time = time.strftime("%Y-%m-%d %H:%M:%S") data = data.replace("@@time@@", now_time) return data.encode("utf-8") url_list = [ ("/index", index), ("/american", american), ("/japan", japan), ("/timer", timer), ] while True: conn, addr = sock.accept() # 等待连接 data = conn.recv(1024) # 接收数据 data = data.decode("utf-8") data_list = data.split() url = data_list[1] if data_list else None print("请求信息====> %s" % url) # 发送数据 conn.send("HTTP/1.1 200 OK\r\nContent-Type: text/html;charset=utf-8\r\n\r\n".encode('utf-8')) func = None for i in url_list: if url == i[0]: func = i[1] break if func: ret = func(url) else: ret = "<h2 style='color:red'>404 not found !</h2>".encode("utf-8") conn.send(ret) conn.close()
总结:web框架,其本质就是socket服务端。
web框架的功能:
1、socket收发消息
2、根据不同的路径返回不同的内容
3、返回动态页面(字符串的替换——模板渲染)
web常用框架分类:
Django: 2、3
flask: 2
tornado: 1、2、3
8、服务器程序和应用程序
对于真实开发中的python web程序来说,一般会分为两部分:服务器程序和应用程序。
服务器程序主要负责对socket服务端进行封装,并在请求到来时,对请求的各种数据进行处理。
应用程序则主要负责具体的逻辑处理。为了方便应用程序的开发,就出现了众多的Web框架,例如:Django、Flask、 Tornado等。不同的框架有不同的开发方式,但是无论如何,开发出的应用程序都要和服务器程序配合,才能为用户提供服务。
WSGI(Web Server Gateway Interface)就是一种规范,它定义了使用Python编写的web应用程序与web服务器程序之间的接口格式,实现web应用程序与web服务器程序间的解耦。
常用的WSGI服务器有uwsgi、Gunicorn。而Python标准库提供的独立WSGI服务器叫wsgiref,Django开发环境用的就是这个模块来做服务器。
好了,接下来我们就使用wsgiref模块来替换我们自己写的web框架的socket server部分,请看下面的代码。
import time from wsgiref.simple_server import make_server # 将返回不同的内容部分封装成函数 def index(url): # 读取index.html页面的内容 with open("index.html", "r", encoding="utf-8") as f: # 此处的HTML文件,同上 data = f.read() # 返回字节数据 return data.encode("utf-8") def timer(url): with open("timer.html", "r", encoding="utf-8") as f: # 此处的HTML文件,同上 data = f.read() now_time = time.strftime("%Y-%m-%d %H:%M:%S") data = data.replace("@@time@@", now_time) return data.encode("utf-8") # 定义一个url和实际要执行的函数的对应关系 url_list = [ ("/index", index), ("/timer", 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 url_list: if i[0] == url: func = i[1] break if func: ret = func(url) else: ret = "<h2 style='color:red'>404 not found !</h2>".encode("utf-8") return [ret, ] if __name__ == '__main__': httpd = make_server('127.0.0.1', 8080, run_server) print("我在8080等你哦...") httpd.serve_forever()
9、jinja2模块
上面的代码已经实现了一个简单的动态,我们完全可以从数据库中查询数据,然后去替换我html中的对应内容,然后再发送给浏览器完成渲染。 这个过程就相当于HTML模板渲染数据。 其本质上就是HTML内容中利用一些特殊的符号来替换要展示的数据。 我们这里用的特殊符号是自己定义的,其实模板渲染有个现成的工具模块,那就是——jinja2。
下载jinja2:
pip install jinja2
下面咱们通过代码,揭开神秘面纱来见识一下jinja2的芳容。
<!--home.html文件内容--> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <h2>姓名:{{name}}</h2> <h2>爱好:</h2> <ul> {% for hobby in hobby_list %} <li>{{hobby}}</li> {% endfor %} </ul> </body> </html>
from wsgiref.simple_server import make_server from jinja2 import Template def home(url): with open("home.html", "r", encoding="utf-8") as f: data = f.read() templata = Template(data) ret = templata.render({"name": "于谦", "hobby_list": ["抽烟", "喝酒", "烫头"]}) return ret.encode("utf-8") url_list = [ ("/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 url_list: if i[0] == url: func = i[1] break if func: ret = func(url) else: ret = "<h2 style='color:red'>404 not found !</h2>".encode("utf-8") return [ret, ] if __name__ == '__main__': httpd = make_server("127.0.0.1", 8989, run_server) print("我在8989等你哦...") httpd.serve_forever()
上面的例子,咱们是在代码里写死的内容,我们思考一下,可不可以从数据库获取数据,来进行页面上内容的替换呢?
总结:
模板的原理就是字符串替换,我们只要在HTML页面中遵循jinja2的语法规则,其内部就会按照指定的语法进行相应的替换,从而达到动态的返回内容。
哎呀,前戏总算结束了,下面终于可以……
Django
有请进入Django官网下载页面:猛戳一下
1、安装Django(建议安装最新LTS版本):
pip3 install django==2.1.7
2、创建咱们第一个Django项目:
下面的命令创建了一个名为"mysite"的Django 项目:
django-admin startproject mysite
3、Django项目目录介绍:
|---mysite # 项目的/目录 |---mysite # 项目目录 |---__init__.py |---settings.py # 配置文件 |---urls.py # 路由系统 ===> url与视图的对应关系 |---wsgi.py # runserver命令就使用wsgiref模块做简单的web server |---manage.py # 管理文件
4、启动运行Django项目:
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:8888 # 0.0.0.0:8888
# 注意:要在manage.py同级目录执行命令
5、Django配置文件:
# 模板文件配置 TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, "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/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, "statics"), ]
6、写自己的第一个页面,感受一下。
四、今日作业
基于Django,使用bootstrap来写一个用户登录页面