一、简单web框架
WSGI:Web Server Gateway Interface
一个简单的web框架:
step1:
#!/usr/bin/env python # -*- coding: utf-8 -*- from wsgiref.simple_server import make_server def application(environ,start_response): start_response("200 OK",[("Content-Type","text/html")]) return [b'<h1>Hello,web!!</h1>'] httpd=make_server("",8080,application) print("Serving HTTP on port 8080....") #开始监听http请求 httpd.serve_forever()
注意:
整个application()函数本身没有涉及到任何解析HTTP的部分,也就是说,底层代码不需要我们自己编写,我们只负责在更高层次上考虑如何响应请求就可以了。 application()函数必须由WSGI服务器来调用。有很多符合WSGI规范的服务器,我们可以挑选一个来用。 Python内置了一个WSGI服务器,这个模块叫wsgiref application()函数就是符合WSGI标准的一个HTTP处理函数,它接收两个参数: //environ:一个包含所有HTTP请求信息的dict对象; //start_response:一个发送HTTP响应的函数。 在application()函数中,调用start_response('200 OK', [('Content-Type', 'text/html')])就发送了HTTP响应的Header,注意Header只能发送一次,也就是只能调用一次start_response()函数。start_response()函数接收两个参数,一个是HTTP响应码,一个是一组list表示的HTTP Header,每 个Header用一个包含两个str的tuple表示。 通常情况下,都应该把Content-Type头发送给浏览器。其他很多常用的HTTP Header也应该发送。 然后,函数的返回值b'<h1>Hello, web!</h1>'将作为HTTP响应的Body发送给浏览器。 有了WSGI,我们关心的就是如何从environ这个dict对象拿到HTTP请求信息,然后构造HTML, 通过start_response()发送Header,最后返回Body。
step2:
print(environ['PATH_INFO']) path=environ['PATH_INFO'] start_response('200 OK', [('Content-Type', 'text/html')]) f1=open("index1.html","rb") data1=f1.read() f2=open("index2.html","rb") data2=f2.read() if path=="/yuan": return [data1] elif path=="/alex": return [data2] else: return ["<h1>404</h1>".encode('utf8')]
step3:
from wsgiref.simple_server import make_server def f1(): f1=open("index1.html","rb") data1=f1.read() return [data1] def f2(): f2=open("index2.html","rb") data2=f2.read() return [data2] def application(environ, start_response): print(environ['PATH_INFO']) path=environ['PATH_INFO'] start_response('200 OK', [('Content-Type', 'text/html')]) if path=="/yuan": return f1() elif path=="/alex": return f2() else: return ["<h1>404</h1>".encode("utf8")] httpd = make_server('', 8502, application) print('Serving HTTP on port 8084...') # 开始监听HTTP请求: httpd.serve_forever()
step4:
from wsgiref.simple_server import make_server def f1(req): print(req) print(req["QUERY_STRING"]) f1=open("index1.html","rb") data1=f1.read() return [data1] def f2(req): f2=open("index2.html","rb") data2=f2.read() return [data2] import time def f3(req): #模版以及数据库 f3=open("index3.html","rb") data3=f3.read() times=time.strftime("%Y-%m-%d %X", time.localtime()) data3=str(data3,"utf8").replace("!time!",str(times)) return [data3.encode("utf8")] def routers(): urlpatterns = ( ('/yuan',f1), ('/alex',f2), ("/cur_time",f3) ) return urlpatterns def application(environ, start_response): print(environ['PATH_INFO']) path=environ['PATH_INFO'] start_response('200 OK', [('Content-Type', 'text/html')]) urlpatterns = routers() func = None for item in urlpatterns: if item[0] == path: func = item[1] break if func: return func(environ) else: return ["<h1>404</h1>".encode("utf8")] httpd = make_server('', 8518, application) print('Serving HTTP on port 8084...') # 开始监听HTTP请求: httpd.serve_forever()
二、 MVC和MTV模式
MVC模式:所谓MVC就是把web应用分为模型(M),控制器(C),视图(V)三层;他们之间以一种插件似的,松耦合的方式连接在一起。模型负责业务对象与数据库的对象(ORM),视图负责与用户的交互(页面),控制器(C)接受用户的输入调用模型和视图完成用户的请求。
Django的MTV模式本质上与MVC模式没有什么差别,也是各组件之间为了保持松耦合关系,只是定义上有些许不同,Django的MTV分别代表:
- Model(模型):负责业务对象与数据库的对象(ORM)
- Template(模版):负责如何把页面展示给用户
- View(视图):负责业务逻辑,并在适当的时候调用Model和Template
此外,Django还有一个url分发器,它的作用是将一个个URL的页面请求分发给不同的view处理,view再调用相应的Model和Template
三、django流程和命令行工具
3.1、django实现流程
1)安装django
pip3 install django #需要添加环境变量
2)创建project
django-admin startproject mysite #创建后会生成如下文件 #---mysite ---settings.py ---url.py ---wsgi.py #---- manage.py(启动文件)
3)创建app
cd mysite python manage.py startapp blog
4)settings配置
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'blog', #添加 ] #------------------------------------ STATICFILES_DIRS=( os.path.join(BASE_DIR,"statics"), )
5)根据需求设计代码
url.py, view.py
6)使用模板
render(req,"index.html")
7)启动项目
python manage.py runserver 127.0.0.1:8090
8)连接数据库,操作数据
model.py
3.2、django的命令行工具
四、django配置文件设置
4.1、静态文件设置
以在pycharm中创建项目为例:
1)创建视图
#编辑blog下的views.py def show_time(request): # return HttpResponse("hello") t=time.ctime() # return render(request,"index.html",locals()) return render(request,"index.html",{"time":t})
2)修改urls.py
from django.contrib import admin from django.urls import path from blog import views urlpatterns = [ path('admin/', admin.site.urls), path('show_time/',views.show_time ), #添加 ]
3)修改setting.py
STATIC_URL = '/static/' #别名 STATICFILES_DIRS=( # os.path.join(BASE_DIR, "blog/static"), #加逗号 绝对路径 os.path.join(BASE_DIR,"blog","static"), #加逗号 绝对路径 )
4)在templates中创建html文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> {% load staticfiles %} <title>Title</title> </head> <body> <h1>hello {{ time }}</h1> {#<script src="/static/jquery-3.1.1.js"></script>#} <script src="{% static 'jquery-3.1.1.js' %}"></script> <script> $("h1").css("color","red") </script> </body> </html>
5)启动服务
6)查看状态
五、Django URL(路由系统)
URL配置就像Django 所支撑网站的目录。它的本质是URL模式以及要为该URL模式调用的视图函数之间的映射表
urlpatterns = [ url(正则表达式, views视图函数,参数,别名), ]
参数说明:
- 一个正则表达式字符串
- 一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
- 可选的要传递给视图函数的默认参数(字典形式)
- 一个可选的name参数
5.1、no_named group
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^articles/2003/$', views.special_case_2003), #url(r'^articles/[0-9]{4}/$', views.year_archive), url(r'^articles/([0-9]{4})/$', views.year_archive), #no_named group url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive), url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail), ] #---------------------------------------------------------------------------------- #1 There’s no need to add a leading slash, because every URL has that. For # example, it’s ^articles, not ^/articles. #2 A request to /articles/2005/03/ would match the third entry in the list. # Django would call the function views.month_archive(request, '2005', '03'). #3 /articles/2005/3/ would not match any URL patterns #4 /articles/2003/ would match the first pattern in the list, not the second one #5 /articles/2003/03/03/ would match the final pattern. Django would call the # functionviews.article_detail(request, '2003', '03', '03').
5.2、named group
The above example used simple, non-named regular-expression groups (via parenthesis) to capture bits of the URL and pass them as positional arguments to a view. In more advanced usage, it’s possible to use named regular-expression groups to capture URL bits and pass them as keyword arguments to a view.
In Python regular expressions, the syntax for named regular-expression groups is (?P<name>pattern)
, where name
is the name of the group and pattern
is some pattern to match.
Here’s the above example URLconf, rewritten to use named groups:
import re ret=re.search('(?P<id>d{3})/(?P<name>w{3})','weeew34ttt123/ooo') print(ret.group()) #123/ooo print(ret.group('id')) #123 print(ret.group('name')) #ooo #----------------------------------------------------------------- from django.conf.urls import url from . import views urlpatterns = [ url(r'^articles/2003/$', views.special_case_2003), url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive), url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive), url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail), ]
5.3、传递额外参数给视图函数
from django.conf.urls import url from . import views urlpatterns = [ url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}), ] #In this example, for a request to /blog/2005/, Django will call views.year_archive(request,year='2005',foo='bar')
5.4、实例
1)配置url.py
from django.contrib import admin from django.urls import path,re_path #导入re_path ==>匹配正则 from blog import views urlpatterns = [ path('admin/', admin.site.urls), path('show_time/',views.show_time ), re_path('article/(d{4})$',views.article_year), #无名分组 re_path('article/(?P<year>d{4})/(?P<month>d{2})/', views.article_year_month), re_path('article/(?P<year>d{4})/(?P<month>d{2})/d+/', views.article_year_month), path("register/", views.register, name="reg"), #别名 ]
2)配置视图函数
def article_year(request,y): return HttpResponse(y) def article_year_month(request,year,month): #year,month名称不可变 return HttpResponse("year:%s month:%s"%(year,month)) def register(request): if request.method=="POST": print(request.POST.get("user")) print(request.POST.get("age")) return HttpResponse("success!") return render(request,"register.html")
3)编写register.html
<!DOCTYPE html> <html lang="en"> <head> {% load staticfiles %} <meta charset="UTF-8"> <script src="/static/jquery-3.1.1.js"></script> <title>Title</title> <style> * { margin: 0; padding: 0 } </style> </head> <body> <h1>学生注册</h1> <hr> <form action="{% url 'reg' %}" method="post"> #使用别名 <p>姓名<input type="text" name="user"></p> <p>年龄<input type="text" name="age"></p> <p>爱好<input type="checkbox" name="hobby" value="1">篮球 <input type="checkbox" name="hobby" value="2">足球 <input type="checkbox" name="hobby" value="3">乒乓球 </p> <p><input type="submit">提交</p> </form> </body> </html>