一、Web框架概述
Web框架本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 # _author_soloLi 4 5 import socket 6 7 def handle_request(client): 8 buf = client.recv(1024) 9 client.send("HTTP/1.1 200 OK\r\n\r\n".encode("utf-8")) 10 client.send("Hello, solo".encode("utf-8")) 11 12 def main(): 13 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 14 sock.bind(('localhost', 8000)) 15 sock.listen(5) 16 while True: 17 connection, address = sock.accept() 18 handle_request(connection) 19 connection.close() 20 21 if __name__ == '__main__': 22 main() 23 #执行上面程序,直接用浏览器访问http://127.0.0.1:8000/就能显示发送的信息: Hello, solo
开发中的python web程序来说,一般会分为两部分:服务器程序和应用程序。
①服务器程序:负责对socket服务器进行封装,并在请求到来时,对请求的各种数据进行整理。
②应用程序:负责具体的逻辑处理。为了方便应用程序的开发,就出现了众多的Web框架,例如:Django、Flask、web.py 等。
不同的框架有不同的开发方式,但是无论如何,开发出的应用程序都要和服务器程序配合,才能为用户提供服务。这样,服务器程序就需要为不同的框架提供不同的支持。这样混乱的局面无论对于服务器还是框架,都是不好的。对服务器来说,需要支持各种不同框架,对框架来说,只有支持它的服务器才能被开发出的应用使用。这时候,标准化就变得尤为重要。我们可以设立一个标准,只要服务器程序支持这个标准,框架也支持这个标准,那么他们就可以配合使用。一旦标准确定,双方各自实现。这样,服务器可以支持更多支持标准的框架,框架也可以使用更多支持标准的服务器;WSGI(Web Server Gateway Interface)是一种规范,它定义了使用python编写的服务器程序和应用程序之间接口格式,实现服务器程序和应用程序间的解耦。
wsgiref:python标准库提供的独立WSGI服务器
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 # _author_soloLi 4 5 from wsgiref.simple_server import make_server 6 7 def RunServer(environ, start_response): 8 start_response('200 OK', [('Content-Type', 'text/html')]) 9 return ['Hello, solo'.encode("utf-8"),] 10 11 if __name__ == '__main__': 12 httpd = make_server('', 8000, RunServer) 13 print("Serving HTTP on port 8000...") 14 httpd.serve_forever()
<1>自定义Web框架 (通过python标准库提供的wsgiref模块)
1.简单框架
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 # _author_soloLi 4 from wsgiref.simple_server import make_server 5 6 def handel_index(): 7 return ['<h1>Hello, index!</h1>'.encode("utf-8"), ] 8 9 def handel_data(): 10 return ['<h1>Hello, data!</h1>'.encode("utf-8"), ] 11 12 URL_DICT={ 13 '/index':handel_index, 14 '/data':handel_data, 15 } 16 17 def RunServer(environ, start_response): 18 start_response('200 OK', [('Content-Type', 'text/html')]) #start_response 封装返回给用户的数据 19 current_url = environ['PATH_INFO'] #environ 客户发来的数据 20 func = None 21 if current_url in URL_DICT: 22 func = URL_DICT[current_url] 23 if func: 24 return func() 25 else: 26 return ['<h1>Error 404</h1>'.encode("utf-8"), ] 27 28 if __name__ == '__main__': 29 httpd = make_server('', 8000, RunServer) 30 print("Serving HTTP on port 8000...") 31 httpd.serve_forever()
2.模板引擎
在上一步骤中,对于所有的login、index均返回给用户浏览器一个简单的字符串,在现实的Web请求中一般会返回一个复杂的符合HTML规则的字符串,所以我们一般将要返回给用户的HTML写在指定文件中,然后再返回。
1 <!DOCTYPE html> 2 <html> 3 <head lang="en"> 4 <meta charset="UTF-8"> 5 <title></title> 6 </head> 7 <body> 8 <form> 9 <input type="text" /> 10 <input type="text" /> 11 <input type="submit" /> 12 </form> 13 </body> 14 </html>
1 <!DOCTYPE html> 2 <html> 3 <head lang="en"> 4 <meta charset="UTF-8"> 5 <title></title> 6 </head> 7 <body> 8 <h1>Index</h1> 9 </body> 10 </html>
1 from wsgiref.simple_server import make_server 2 3 def handel_index(): 4 f = open('index.html','rb') 5 data = f.read() 6 return [data,] 7 # return ['<h1>Hello, index!</h1>'.encode("utf-8"), ] 8 9 def handel_data(): 10 f = open('data.html','rb') 11 data = f.read() 12 return [data,] 13 # return ['<h1>Hello, data!</h1>'.encode("utf-8"), ] 14 15 URL_DICT={ 16 '/index':handel_index, 17 '/data':handel_data, 18 } 19 20 def RunServer(environ, start_response): 21 start_response('200 OK', [('Content-Type', 'text/html')]) #start_response 封装返回给用户的数据 22 current_url = environ['PATH_INFO'] #environ 客户发来的数据 23 func = None 24 if current_url in URL_DICT: 25 func = URL_DICT[current_url] 26 if func: 27 return func() 28 else: 29 return ['<h1>Error 404</h1>'.encode("utf-8"), ] 30 31 if __name__ == '__main__': 32 httpd = make_server('', 8000, RunServer) 33 print("Serving HTTP on port 8000...") 34 httpd.serve_forever()
3.返回动态页面数据
对于上述代码,虽然可以返回给用户HTML的内容以现实复杂的页面,但是还是存在问题:如何给用户返回动态内容?
①自定义一套特殊的语法,进行替换
②使用开源工具jinja2,遵循其指定语法
1 from wsgiref.simple_server import make_server 2 3 def handel_index(): 4 f = open('index.html','rb') 5 data = f.read() 6 data = data.replace(b'Index',"小祥祥吃骨头".encode("utf-8")) 7 return [data,] 8 # return ['<h1>Hello, index!</h1>'.encode("utf-8"), ] 9 10 def handel_data(): 11 f = open('data.html','rb') 12 data = f.read() 13 return [data,] 14 # return ['<h1>Hello, data!</h1>'.encode("utf-8"), ] 15 16 URL_DICT={ 17 '/index':handel_index, 18 '/data':handel_data, 19 } 20 21 def RunServer(environ, start_response): 22 start_response('200 OK', [('Content-Type', 'text/html')]) #start_response 封装返回给用户的数据 23 current_url = environ['PATH_INFO'] #environ 客户发来的数据 24 func = None 25 if current_url in URL_DICT: 26 func = URL_DICT[current_url] 27 if func: 28 return func() 29 else: 30 return ['<h1>Error 404</h1>'.encode("utf-8"), ] 31 32 if __name__ == '__main__': 33 httpd = make_server('', 8000, RunServer) 34 print("Serving HTTP on port 8000...") 35 httpd.serve_forever()
<2>MVC/MTV
MVC
Model View Controller
数据库 模板文件 业务处理
MTV
Model Template View
数据库 模板文件 业务处理
django采用的是MTV模式。
二、Django概述
<0>Django生命周期
Django大致工作流程:
① 客户端发送请求(get/post)经过web服务器、Django中间件、 到达路由分配系统
② 路由分配系统根据提取 request中携带的的url路径(path)与视图函数映射关系列表中,匹配到1个视图函数,foo(request)执行;
③ 视图函数 使用原生SQL或者ORM去数据库拿到数据,在服务端进行渲染(模板+数据渲染)
④ 视图函数return一个 response对象 返回客户端
<1>Django基本配置
Python的WEB框架有Django、Tornado、Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM、模型绑定、模板引擎、缓存、Session等诸多功能。
0、Django安装(略,自己百度去。。。)
1、创建Django工程
django-admin startproject 工程名 #django-admin startproject mysite # 终端上直接输入,创建sitename项目名 mysite目录结构: - mysite # 对整个程序进行配置 - init - settings # 配置文件 - urls # URL对应关系 - wsgi # 遵循WSIG规范;Django里面没封装socket,当进行socket数据交互时要用到wsgi,一般用第三方模块uwsgi+nginx - manage.py # 管理Django程序:
2、创建APP
cd 工程名 python manage.py startapp 应用名 #python manage.py startapp cmdb # 目录结构 - cmdb - migrations #数据库操作记录(只是修改表结构的记录) - init #表示python数据包(python3中有无均可) - admin #Django为我们提供的后台管理 - apps #配置当前app - models #创建数据库表结构,写指定的类,通过命令可以创建数据库结构 - tests #单元测试 - views #写业务逻辑代码,最重要的就是这个文件了
3、配置数据库(暂时默认不修改)
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME':'dbname', 'USER': 'root', 'PASSWORD': 'xxx', 'HOST': '', 'PORT': '', } } # 由于Django内部连接MySQL时使用的是MySQLdb模块,而python3中还无此模块,所以需要使用pymysql来代替 # 如下设置放置的与project同名的配置的 __init__.py文件中 import pymysql pymysql.install_as_MySQLdb()
4、配置静态文件
#①创建static目录:放置css、js样式文件 #②settings.py STATICFILES_DIRS = ( os.path.join(BASE_DIR, 'static'), ) #③templates目录下的xx.html(可以使用static目录里面的css、js样式) <link rel="stylesheet" href="/static/commons.css" />
5、配置模板路径
#settings.py 'DIRS': [os.path.join(BASE_DIR, 'templates')],
6、注释 csrf(暂时)
#settings.py MIDDLEWARE = [ #'django.middleware.csrf.CsrfViewMiddleware', ]
7、定义路由规则(#url)
#url.py #"login" --> 函数名 (暂时记一种) urlpatterns = [ url(r'^login', views.login), ]
8、定义视图函数(#view)
#app下views.py def func(request): # request 包含了用户提交的所有信息 # request.method GET / POST # http://127.0.0.1:8009/home?nid=123&name=alex # request.GET.get('',None) # 获取请求发来的而数据 # request.POST.get('',None) # return HttpResponse("字符串") # return render(request, "HTML模板的路径") # return redirect('/只能填URL')
三、路由分配系统(URL)
定义:project目录中的urls.py文件中, 以一个url()实例的列表urlpatterns,记录了可以访问到该站点的url 和 视图函数一一对应关系
作用:当request请求到达路由系统,Django通过request中携带的path 遍历这个关系表,匹配到对应的视图函数,break;(所以1个 url 只能从路由关系表中自上而下匹配到1个视图函数)
方式:①通过get请求携带参数的方式向server端传数据; https://i.cnblogs.com/%EF%BC%9Fid=1&name=solo
②通过path路径的方式向server端传值(以下主要介绍②);
注意事项:按位置、按关键字,路由系统只能用1种,不能混合使用;
1、单一路由对应
① url(r'^index/', views.index), url(r'^域名',对应的处理函数) 注意不要忘了写 ^ 表示正则匹配以。。开头的URL
#编写URLconf的注意: #若要从url中捕获一个值,需要在它周围设置一对圆括号 #不需要添加一个前导的反斜杠,如应该写作'test/',而不应该写作'/test/' #每个正则表达式前面的r表示字符串不转义 #请求的url被看做是一个普通的python字符串,进行匹配时不包括get或post请求的参数及域名
2、基于正则的路由(未分组)
② url(r'^detail-(\d+).html/', views.detail), #通过位置参数传递给视图
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {% for k,item in user_dict.items %} <li><a target="_blank" href="/detail-{{ k }}.html">{{ item.name}}</a></li> {% endfor %} </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h2>详细信息</h2> <h4>用户名:{{ detail_info.name }}</h4> <h4>邮箱:{{ detail_info.email }}</h4> </body> </html>
from django.conf.urls import url,include from django.contrib import admin from cmdb import views urlpatterns = [ url(r'^index', views.index), url(r'^detail-(\d+).html/', views.detail), ]
USER_DICT = { '1':{'name':'root1','email':'root@live.com'}, '2':{'name':'root2','email':'root@live.com'}, '3':{'name':'root3','email':'root@live.com'}, '4':{'name':'root4','email':'root@live.com'}, } def index(request): return render(request,"index.html",{"user_dict":USER_DICT}) def detail(request,nid): # nid指定的是(\d+)里的内容 detail_info = USER_DICT[nid] return render(request, "detail.html", {"detail_info": detail_info})
3、基于正则的路由(分组)
③ url(r'^detail-(\d+)-(\d+).html', views.detail), #严格按照分组顺序传参数,一个出错,所有的都跟着出错
④ url(r'^detail-(?P<nid>\d+)-(?P<uid>\d+).html/', views.detail) #可以不按照顺序传参数
#参数匹配规则:优先使用命名参数,如果没有命名参数则使用位置参数
#每个捕获的参数都作为一个普通的python字符串传递给视图
#性能:urlpatterns中的每个正则表达式在第一次访问它们时被编译,这使得系统相当快
from django.conf.urls import url,include from django.contrib import admin from cmdb import views urlpatterns = [ url(r'^index', views.index), url(r'^detail-(?P<nid>\d+)-(?P<uid>\d+).html/', views.detail),<br> # nid=\d+ uid=\d+ ]
def detail(request,**kwargs): print(kwargs) #{'nid': '4', 'uid': '3'} nid = kwargs.get("nid") detail_info = USER_DICT[nid] return render(request, "detail.html", {"detail_info": detail_info})
2、url(r'^detail-(\d+).html', views.detail), 3、url(r'^detail-(?P<nid>\d+)-(?P<uid>\d+).html', views.detail) PS: def detail(request, *args,**kwargs): pass 实战: a. #③ url(r'^detail-(\d+)-(\d+).html', views.detail), def func(request, nid, uid): pass def func(request, *args): args = (2,9) def func(request, *args, **kwargs): args = (2,9) b. #④ url(r'^detail-(?P<nid>\d+)-(?P<uid>\d+).html', views.detail) def func(request, nid, uid): pass def funct(request, **kwargs): kwargs = {'nid': 1, 'uid': 3} def func(request, *args, **kwargs): args = (2,9)
4、为路由映射设置名称
对URL路由关系进行命名, ***** 以后可以根据此名称生成自己想要的URL *****
设置名称之后,可以在不同的地方调用,如:
--模板中使用生成URL {% url 'i2' 2012 %}
--函数中使用生成URL reverse('i2', args=(2012,)) 路径:django.urls.reverse
--Model中使用获取URL 自定义get_absolute_url() 方法
class NewType(models.Model): caption = models.CharField(max_length=16) def get_absolute_url(self): """ 为每个对象生成一个URL 应用:在对象列表中生成查看详细的URL,使用此方法即可!!! :return: """ # return '/%s/%s' % (self._meta.db_table, self.id) # 或 from django.urls import reverse return reverse('NewType.Detail', kwargs={'nid': self.id})
<body> {#第一种方法i1 路径asdfasdfasdf/#} {#<form action="{% url "i1" %}" method="post">#} {#第二种方法i2 路径yug/1/2/#} {#<form action="{% url "i2" 1 2 %}" method="post">#} {#第三种方法i3 路径buy/1/9//#} <form action="{% url "i3" pid=1 nid=9 %}" method="post"> <p><input name="user" type="text" placeholder="用户名"/></p> <p><input name="password" type="password" placeholder="密码"/></p> <p><input type="submit" value="提交"/></p> </form> </body>
from django.conf.urls import url,include from django.contrib import admin from cmdb import views urlpatterns = [ url(r'^asdfasdfasdf/', views.index, name='i1'), #第一种方式i1 url(r'^yug/(\d+)/(\d+)/', views.index, name='i2'), #第二种方式i2 url(r'^buy/(?P<pid>\d+)/(?P<nid>\d+)/', views.index, name='i3'), #第三种方式i3 ]
def index(request,*args,**kwargs): return render(request,"index.html")
对URL路由关系进行命名, ***** 以后可以根据此名称生成自己想要的URL ***** #settings.py url(r'^asdfasdfasdf/', views.index, name='i1'), url(r'^yug/(\d+)/(\d+)/', views.index, name='i2'), url(r'^buy/(?P<pid>\d+)/(?P<nid>\d+)/', views.index, name='i3'), #views.py def func(request, *args, **kwargs): from django.urls import reverse url1 = reverse('i1') # url1=asdfasdfasdf/ url2 = reverse('i2', args=(1,2,)) # url2=yug/1/2/ url3 = reverse('i3', kwargs={'pid': 1, "nid": 9}) # url3=buy/1/9/ #xxx.html {% url "i1" %} # --> asdfasdfasdf/ {% url "i2" 1 2 %} # --> yug/1/2/ {% url "i3" pid=1 nid=9 %} # --> buy/1/9/ 注: # 当前的URL request.path_info
5、request.path_info:获取客户端当前的访问链接
request.path:获取当前客户端的访问路径
<form action="{{ request.path_info }}" method="post"> <p><input name="user" type="text" placeholder="用户名"/></p> <p><input name="password" type="password" placeholder="密码"/></p> <p><input type="submit" value="提交"/></p> </form>
from django.conf.urls import url,include from django.contrib import admin from cmdb import views urlpatterns = [ url(r'^index', views.index), ]
def index(request): print(request.path_info) #获取客户端当前的访问链接 # / index return render(request,"index.html",{"user_dict":USER_DICT})
6、路由分发(多级路由)
include()
#使用include可以去除urlconf的冗余
#匹配过程:先与主URLconf匹配,成功后再用剩余的部分与应用中的URLconf匹配
from django.conf.urls import url,include from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^cmdb/', include("app01.urls")), #调整到app01目录中的urls.py文件;注意include的是字符串形式的文件路径 url(r'^monitor/', include("app02.urls")), url(r'^login', views.login), ]
from django.conf.urls import url,include from django.contrib import admin from app01 import views urlpatterns = [ url(r'^login/', views.login), ]
from django.shortcuts import HttpResponse from django.shortcuts import render from django.shortcuts import redirect def login(request): # request 包含了用户提交的所有信息 # print(request.method) error_msg='' if request.method == 'POST': user = request.POST.get('user',None) pwd = request.POST.get('pwd',None) if user == 'root' and pwd == '123': #去跳转 return redirect('http://www.baidu.com') else: error_msg = 'SB! it is wrong' return render(request,'login.html',{'error_msg':error_msg})
from django.shortcuts import render,HttpResponse # Create your views here. def login(requst): return HttpResponse('app02 login')
from django.conf.urls import url,include from django.contrib import admin from app02 import views urlpatterns = [ url(r'^login/', views.login), ]
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/commons.css" /> <style> label{ width: 80px; text-align: right; display: inline-block; } </style> </head> <body> <form action="/login" method="post"> <p> <label for="username">用户名:</label> <input id="username" name="user" type="text" /> </p> <p> <label for="password">密码:</label> <input id="password" name="pwd" type="password" /> <input type="submit" value="提交" /> <span style="color: red;">{{ error_msg }}</span> </p> </form> <script src="/static/jquery.min.js"></script> </body> </html>
7、默认值(添加额外的参数)
from django.conf.urls import url from django.contrib import admin from cmdb import views urlpatterns = [ url(r'^index/', views.index, {'name':'root'}), ]
def index(request,name): print(name) return HttpResponse('OK') #root
8、命名空间
在django中每一个请求的url都要有一条路由映射,这样才能将请求交给对一个的view中的函数去处理。其他大部分的Web框架则是对一类的url请求做一条路由映射,从而是路由系统变得简洁。
配置url时为了解决url硬编码的问题,常常会使用命名空间来表示一个url。
命名空间:是表示标识符的可见范围。一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。这样,在一个新的命名空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其它命名空间中。#在include中通过namespace定义命名空间,用于反解析
#URL的反向解析
如果在视图、模板中使用硬编码的链接(href="/polls/{{ poll.id }}/"),在urlconf发生改变时,维护是一件非常麻烦的事情
解决:在做链接时,通过指向urlconf的名称,动态生成链接地址
视图:使用django.core.urlresolvers.reverse()函数
模板:使用url模板标签
from django.conf.urls import url,include urlpatterns = [ url(r'^a/', include('cmdb.urls', namespace='author-polls')), url(r'^b/', include('cmdb.urls', namespace='publisher-polls')), ]
from django.conf.urls import url from cmdb import views urlpatterns = [ url(r'^index/', views.detail, name='detail'), ]
from django.shortcuts import HttpResponse from django.shortcuts import reverse def detail(request): url = reverse('author-polls:detail') print(url) return HttpResponse('OK')
{% url 'author-polls:detail' %}
9、生成url路径(path_info+reverse)
from.import models def article(request,*args,**kwargs): # 第一种方式利用path_info,访问的url print(request.path_info) # /article/0-0.html/ # 第二种方式用reverse,自己生成 # 需要配合urls.py文件 url(r'...',views.article ,name='article') from django.urls import reverse url = reverse('article',kwargs=kwargs) print(url) # /article/0-0.html/
四、视图函数
定义:视图就是一个Python函数,被定义在views.py中。
配置:定义完成视图后,需要配置urlconf(正则表达式+视图)
作用:Django使用正则表达式匹配请求的URL,一旦匹配成功(只匹配路径部分,即除去域名、参数后的字符串),则调用相对应的视图。返回的响应可以是一张网页的HTML内容,一个重定向,一个404错误等等。
404 (page not found) defaults.page_not_found(request, template_name='404.html') 默认的404视图将传递一个变量给模板:request_path,它是导致错误的URL 如果Django在检测URLconf中的每个正则表达式后没有找到匹配的内容也将调用404视图 如果在settings中DEBUG设置为True,那么将永远不会调用404视图,而是显示URLconf 并带有一些调试信息 500 (server error) defaults.server_error(request, template_name='500.html') 在视图代码中出现运行时错误 默认的500视图不会传递变量给500.html模板 如果在settings中DEBUG设置为True,那么将永远不会调用505视图,而是显示URLconf 并带有一些调试信息 400 (bad request) defaults.bad_request(request, template_name='400.html') 错误来自客户端的操作 当用户进行的操作在安全方面可疑的时候,例如篡改会话cookie
表单交互
1、获取表单提交类型做相应处理
#最终效果:当用户第一次访问时显示正常页面,输入用户名密码正确时调整到百度;错误时页面显示‘SB! it is wrong’
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 <link rel="stylesheet" href="/static/commons.css" /> 7 <style> 8 label{ 9 width: 80px; 10 text-align: right; 11 display: inline-block; 12 } 13 </style> 14 </head> 15 <body> 16 <form action="/login" method="post"> 17 <p> 18 <label for="username">用户名:</label> 19 <input id="username" name="user" type="text" /> 20 </p> 21 <p> 22 <label for="password">密码:</label> 23 <input id="password" name="pwd" type="password" /> 24 <input type="submit" value="提交" /> 25 <span style="color: red;">{{ error_msg }}</span> 26 </p> 27 </form> 28 <script src="/static/jquery.min.js"></script> 29 </body> 30 </html>
1 from django.shortcuts import HttpResponse 2 from django.shortcuts import render 3 from django.shortcuts import redirect 4 5 def login(request): 6 # request 包含了用户提交的所有信息 7 # print(request.method) 8 9 error_msg='' 10 if request.method == 'POST': 11 user = request.POST.get('user',None) 12 pwd = request.POST.get('pwd',None) 13 if user == 'root' and pwd == '123': 14 #去跳转 15 return redirect('http://www.baidu.com') 16 else: 17 error_msg = 'SB! it is wrong' 18 19 return render(request,'login.html',{'error_msg':error_msg})
--commons.css
--jquery_min.js
2、模拟数据库交互,循环列表渲染页面
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body style="margin: 0"> 8 <div style="height: 48px;background-color: #dddddd"></div> 9 <div> 10 <form action="/home" method="post"> 11 <input type="text" name="username" placeholder="用户名" /> 12 <input type="text" name="email" placeholder="邮箱"/> 13 <input type="text" name="gender" placeholder="性别"/> 14 <input type="submit" value="添加" /> 15 </form> 16 </div> 17 <div> 18 <table> 19 {% for row in user_list %} 20 <tr> 21 <td>{{ row.username }}</td> 22 <td>{{ row.gender }}</td> 23 <td>{{ row.email }}</td> 24 </tr> 25 {% endfor %} 26 27 </table> 28 </div> 29 30 31 </body> 32 </html>
1 from django.conf.urls import url 2 from django.contrib import admin 3 from cmdb import views 4 5 6 urlpatterns = [ 7 url(r'^admin/', admin.site.urls), 8 # url(r'^login', views.login), 9 url(r'^home', views.home), 10 ]
1 from django.shortcuts import HttpResponse 2 from django.shortcuts import render 3 from django.shortcuts import redirect 4 5 USER_LIST = [ 6 {'id': 1, 'username': 'alex', 'email': '1109913149@qq.com', "gender": 'male'}, 7 {'id': 2, 'username': 'solo', 'email': '1109913149@qq.com', "gender": 'male'}, 8 {"id": 3,'username': 'seven', 'email': '1109913149@qq.com', "gender": 'male'}, 9 ] 10 11 def home(request): 12 if request.method == "POST": 13 # 获取用户提交的数据 POST请求中 14 u = request.POST.get('username') 15 e = request.POST.get('email') 16 g = request.POST.get('gender') 17 temp = {'username': u, 'email': e, "gender": g} 18 USER_LIST.append(temp) 19 return render(request, 'home.html', {'user_list': USER_LIST})
3、表单交互,获取checkbox多个值
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 <form action="/login" method="POST" > 9 <p> 10 男:<input type="checkbox" name="favor" value="11"/> 11 女:<input type="checkbox" name="favor" value="22"/> 12 戴利祥:<input type="checkbox" name="favor" value="33"/> 13 </p> 14 <input type="submit" value="提交"/> 15 </form> 16 </body> 17 </html>
1 from django.conf.urls import url 2 from django.contrib import admin 3 from cmdb import views 4 5 6 urlpatterns = [ 7 url(r'^admin/', admin.site.urls), 8 url(r'^login', views.login), 9 # url(r'^home', views.home), 10 ]
1 def login(request): 2 #checkbox 多选框 3 if request.method == "POST": 4 favor_list = request.POST.getlist("favor") #getlist获取多个值 5 print(favor_list) #多选框获取到的是列表格式 6 #['11', '22', '33'] 7 return render(request,"login.html") 8 elif request.method == "GET": 9 return render(request,"login.html") 10 else: 11 print("other")
注:select多选时跟上面程序一样都用getlist进行获取
4、表单交互,上传文件file
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 <form action="/login" method="POST" enctype="multipart/form-data"> 9 <p> 10 <input type="file" name="files"/> 11 </p> 12 <input type="submit" value="提交"/> 13 </form> 14 </body> 15 </html>
1 def login(request): 2 #file 上传文件 3 if request.method == "POST": 4 obj = request.FILES.get('files') #用files获取文件对象 5 if obj: 6 print(obj, type(obj), obj.name) 7 # test.jpg <class 'django.core.files.uploadedfile.InMemoryUploadedFile'> test.jpg 8 import os 9 file_path = os.path.join('upload', obj.name) 10 f = open(file_path, "wb") 11 for item in obj.chunks(): #chunks表示所有的数据块,是个迭代器 12 f.write(item) 13 f.close() 14 return render(request,"login.html") 15 elif request.method == "GET": 16 return render(request,"login.html") 17 else: 18 print("other")