时间:2022-08-29 02:36:01 | 来源:网站运营
时间:2022-08-29 02:36:01 来源:网站运营
python在网络方面的应用非常广泛,这里我们关注一下网站服务器及web开发部分。python几行代码就可以搭建一个web服务器,然后使用python语言来开发后台服务。之前的文章我对web服务做了较为详细的介绍,这个服务主要包括http的各种类型请求,如get、post等常规请求。对于web开发,不同页面之间的跳转、数据传输通信、网页存储、缓存等是基础知识,如果采用原生python来写估计难度还是很大的,所以感谢前人栽树,有了一些成熟的框架模块,我们再来使用时就非常方便。当然至于python用于web服务的性能如何,这里我们不做讨论。在web开发框架部分,较为知名的包括django、flask等框架。from flask import Flask #导入Flask类app=Flask(__name__) #实例化并命名为app实例if __name__=="__main__": app.run(port=2020,host="127.0.0.1",debug=True) #调用run方法,设定端口号,启动服务
执行该文件,在终端就有如下提示:from flask import Flaskapp=Flask(__name__)@app.route('/')def index(): return 'welcome to my webpage!'if __name__=="__main__": app.run(port=2020,host="127.0.0.1",debug=True)
代码中使用了装饰器来制定路由url,具体写法如下:@app.route('/') #调用route路由方法,括号里给定参数,/符号默认为首页@app.route('/home/user') #调用route路由方法,/home/user定位到访问user方法页面
在定制了路由url后,还需要给定一个实现方法,使用python定义函数的方式来实现,如上index函数,返回一个字符串welcome to my webpage。也就是当路由url定位到首页时,就调用这个index函数,此时就会在浏览器上输出这个字符串内容。@app.route('/')def index(): return '<h3>welcome to my webpage!</h3><hr><p style="color:red">输出语句测试</p>'
再重新运行py文件,浏览器刷新一下就显示为:from flask import Flask,render_template #导入render_template模块app=Flask(__name__)@app.route('/')def index(): return render_template("index.html") #调用render_template函数,传入html文件参数if __name__=="__main__": app.run(port=2020,host="127.0.0.1",debug=True)
如果这样运行,pycharm终端会提示报错,因为找不到index.html文件。flask框架在使用这个模板函数时,默认去寻找项目文件夹下的templates文件夹里的html文件。因此我们需要先新建一个templates文件夹,然后在里面新建一个html文件,项目结构及内容参考如下:{% python语句 %}{{ 变量 }}
我们继续将上述案例代码修改一下,来测试一下数据传输效果:from flask import Flask,render_templateapp=Flask(__name__)@app.route('/')def index(): msg="my name is caojianhua, China up!" return render_template("index.html",data=msg) #加入变量传递if __name__=="__main__": app.run(port=2020,host="127.0.0.1",debug=True)
然后在index.html中修改:<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>welcome to 2020</title></head><body> welcome to my webpage <hr> <p>这是采用render_template模板方法获得的内容:</p> <br> {{data}} #显示出传递过来的变量内容</body></html>
保存后重新启动web服务,然后浏览器上刷新一下(默认浏览器地址栏还是127.0.0.1:2020访问首页):<img src="{{ url_for('static',filename='img/main.jpg')}}" alt="">
使用jinjia2模板的url_for路由函数,指定为static目录下,filename指向具体图片。from flask import Flask,render_templateapp=Flask(__name__)@app.route('/')def index(): msg="my name is caojianhua, China up!" return render_template("index.html",data=msg)@app.route('/news') #增加一个news页面def newspage(): newsContent="全国上下一心支持武汉,武汉加油!" return render_template("news.html",data=newsContent)app.route('/product') #增加一个product页面def productpage(): return render_template("product.html") if __name__=="__main__": app.run(port=2020,host="127.0.0.1",debug=True)
然后根据路由设定,在templates文件夹下新增两个网页文件,news.html和project.html。<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>news</title></head><body><p>今日新闻</p><p>2020年1月28日0-24时,浙江省报告新型冠状病毒感染的肺炎新增确诊病例123例,新增重症病例11例,新增出院病例2例。</p><hr><p style="color:red">{{data}}</p></body></html>
接下来重启一下main.py文件,在浏览器地址栏输入: 127.0.0.1:2020/news,即可获得如下页面:<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>news</title></head><body><p>今日新闻</p><p>2020年1月28日0-24时,浙江省报告新型冠状病毒感染的肺炎新增确诊病例123例,新增重症病例11例,新增出院病例2例。</p><hr><p style="color:red">{{data}}</p><p><a href="/ ">回到首页</a></p> #回首页超链接<p> <a href="{{ url_for('productpage') }}">去看产品页</a></p> #产品页链接</body></html>
代码中url_for函数给定参数是路由页面的函数名,如本例中的产品页,main.py函数中路由为/product,但函数名为productpage,这里a超链接需要给定函数名即projectpage,<a href="{{ url_for('productpage') }} " 。回首页超链接直接给/即可,<a href="/">。也可以直接使用路径方式,如/product,就是寻找main.py文件的product路由名,这也是指向了productpage函数。<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>welcome to 2020</title></head><body> welcome to my webpage<ul> <li><a href="/news">查看新闻</a></li> <li><a href="/product">查看产品</a></li></ul> <hr> <p>这是采用render_template模板方法获得的内容:</p> <br> {{data}}</body></html>
首页效果如下:<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>welcome to 2020</title></head><body> welcome to my webpage<ul> <li><a href="/news">查看新闻</a></li> <li><a href="{{ url_for('productpage',a=50) }}">查看产品</a></li> #注意超链接带参数a传递</ul> <hr> <p>这是采用render_template模板方法获得的内容:</p> <br> {{data}}</body></html>
因为要跳转到product装饰器位置,就需要将其修改一下如下:@app.route('/product/<a>',methods=['GET'])def productpage(a): return render_template("product.html",data=a)
此时在product.html中增加一行读取这个data的值:<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>product</title></head><body>传递过来的值为{{data}}<p>库克表示,他不会就5G方面的未来苹果产品发表评论,但表示5G处于“在全球范围内进行部署的早期阶段”。苹果对其现有的iPhone产品线“感到骄傲”</p></body></html>
此时从首页点击查看产品链接时,就可以顺利将参数传递到product.html页面了。<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>welcome to 2020</title> <style> .rr{float:left;width:50%;}</style></head><body><div style="width:600px;height:30px"> <div class="rr"> welcome to my webpage </div> <div class="rr"> {% if data != '' %} #如果存在data变量的值,就显示用户姓名,以及注销链接 <a href="#">{{ data}}</a> <a href="#">注销</a> {% else %} #否则就显示登录与注册链接 <a href="#">登陆</a> <a href="#">注册</a> {% endif %} </div> <div style="clear:both;"></div></div><img src="{{ url_for('static',filename='img/main.jpg')}}" alt=""><hr><ul> <li><a href="/news">查看新闻</a></li> <li><a href="/product">查看产品</a></li></ul></body></html>
当点击登录链接时,路由指向main.py中的login,该函数直接跳转到login.html页面里。在main.py中这部分代码如下:@app.route('/login')def loginpage(): return render_template("login.html")
在login.html里设计一个表单输入,注意form的action指向路由:<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>userlogin</title></head><body><center> <h3>用户登录页面</h3> <div> <form action="/loginProcess" method="post"> 用户名: <input type="text" name="nm"><br> 用户密码: <input type="password" name="pwd"> <br> <input type="submit" name="submit" value="登录"> </form> </div></center></body></html>
form中的action路由指向为loginProcess,此时我们在main.py中增加这个路由装饰器及对应的函数,同时由于涉及表单数据的接收,此时就需要导入flask的request包,调用其form属性,具体用法如下:data=request.form #data为一个接收表单的数组对象或者 name=request.form['nm'] #接收到用户名文本框的输入并赋值给name变量
此时loginProcess路由代码如下:@app.route('/loginProcess',methods=['POST','GET'])def loginProcesspage(): if request.method=='POST': nm=request.form['nm'] #获取姓名文本框的输入值 pwd=request.form['pwd'] #获取密码框的输入值 if nm=='cao' and pwd=='123': return render_template("index.html",data=nm) #使用跳转html页面路由 else: return 'the username or userpwd does not match!'
这里的当输入值满足条件时,使用了render_template来进行页面渲染,实际上是不合适的。不过为了说明表单输入的处理方式,我们先这样运行,如此就基本实现了表单输入的接收。return redirect(url_for('index'))
还是使用到url_for方法,寻找到对应的路由处理函数。不过不像rendertemplate可以传递参数,redirect默认参数里没有传值功能,因此如这种用户注册,需要使用一下会话session缓存技术。也就是将正确的用户名保存到session数组变量中。使用的时候先从flask库中导入session模块,同时为了保证安全,还需要给定一个app.secret_key: app.secret_key='any random string' #这里我们直接给定一个密钥
然后在刚才登录loginProcess代码中增加一个session会话存储功能:@app.route('/loginProcess',methods=['POST','GET'])def loginProcesspage(): if request.method=='POST': nm=request.form['nm'] pwd=request.form['pwd'] if nm=='cao' and pwd=='123': session['username']=nm #使用session存储方式,session默认为数组,给定key和value即可 return redirect(url_for('index')) #重定向跳转到首页 else: return 'the username or userpwd does not match!'
接下来在首页index.html页面中修改一下:<div class="rr"> {% if session['username'] == 'cao' %} #如果session中用户名为cao,以及注销链接 <a href="#">{{ session['username']}}</a> <a href="#">注销</a>
这样就完整实现了用户的登录,当然这里的用户目前只限定了一个人名cao。如下为用户登录界面以及登录后首页的效果。from flask import gg.name='cao'
在当前页面请求中就可以直接使用g的值了。@app.context_processordef common(): isLogin=False return isLogin
这样代码中的isLogin变量就会在项目业务中通用。class dbUtils: def __init__(self, dbName): # 连接数据库 import sqlite3 self.conn = sqlite3.connect(dbName) def db_action(self, sql, actionType=0): # 进行相关业务操作 try: res = self.conn.execute(sql) if actionType == 1: # 当操作类型为1时代表为查询业务,返回查询列表 return res.fetchall() else: # 当操作类型不为1时代表为新增、删除或更新业务,返回逻辑值 return True except ValueError as e: print(e) def close(self): # 关闭数据库 self.conn.commit() self.conn.close()#1.创建数据库db=dbUtils('web2020.db')#2.创建新闻表sql='create table news (newsid int, content text, author text)'if db.db_action(sql,0)==True: print("创建新闻表成功!")else: print("try again1")#3.新增新闻sql= "insert into news values(1,'武汉疫情非常严重,口罩等急需物品短缺','cao')," / "(2,'全国人民都给武汉加油,疫情肯定会控制住','cao')"if db.db_action(sql,0)==True: print("新增新闻表成功!")else: print("try again1")db.close()
执行后,就完成了新闻表的创建,同时新增了两条新闻。@app.route('/news')def newspage(): import dbutil #导入dbutil模块,就是上面这个文件 db=dbutil.dbUtils('web2020.db') #链接web2020数据库 sql='select * from news' #组装查询sql语句 newslist=db.db_action(sql,1) #查询处理并返回列表 db.close() #关闭数据库 return render_template("news.html",data=newslist) #将数据传递到news.html页面中
然后在news.html页面中使用jinjia2模板中的语法来读取两条新闻内容:<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>news</title></head><body><p>今日新闻</p>{% for item in data %} #采用循环来读取列表中的内容 <p style="color:red">{{item}}</p>{% endfor %}<hr><p><a href="/ ">回到首页</a></p><p> <a href="{{ url_for('productpage',a=50) }}">去看产品页</a></p></body></html>
运行结果如下:from flask import Blueprint, render_template, session, url_for,requestfrom werkzeug.utils import redirectuser=Blueprint('user',__name__) #蓝图使用方法,参数里给定文件名,还可以给定url前缀@user.route('/login') #使用user的路由配置def loginpage(): return render_template("login.html")@user.route('/loginProcess',methods=['POST','GET']) #使用user 的路由配置def loginProcesspage(): if request.method=='POST': nm=request.form['nm'] pwd=request.form['pwd'] if nm=='cao' and pwd=='123': session['username']=nm print(session['username']) return redirect(url_for('index')) else: return 'the username or userpwd does not match!'
可以看到其中主要的语句为:user=Blueprint('user',__name__) #蓝图使用方法,参数里给定文件名,还可以给定url前缀
将user.py文件名user作为蓝图来使用传入Blueprint方法中,另外如果需要还可以在这里加入url前缀限定:url_prefix=‘/user'。整个参数包括有很多,这里截图如下:from flask import Blueprint, render_templatenews=Blueprint('news',__name__) #news蓝图@news.route('/news')def newspage(): import dbutil db=dbutil.dbUtils('web2020.db') sql='select * from news' newslist=db.db_action(sql,1) return render_template("news.html",data=newslist)@news.route('/news/edit')def newsEditpage(): return '/news/edit'
如下为product.py蓝图:from flask import Blueprint, render_templateproduct=Blueprint('product',__name__)@product.route('/product')def productpage(): return render_template("product.html")
这样就将各个业务单独分开处理了,最后我们在main.py主路由文件中将上述的文件采用蓝图注册方式导入即可。from flask import Flask, render_template, url_for, request, redirect, sessionfrom news import news #导入news蓝图from user import user #导入user蓝图from product import product #导入product蓝图app=Flask(__name__)app.secret_key='any random string'urls=[news,user,product] #将三个路由构建数组for url in urls: app.register_blueprint(url) #将三个路由均实现蓝图注册到主app应用上@app.route('/')def index(): userinfo='' return render_template("index.html",data=userinfo)if __name__=="__main__": print(app.url_map) #打印url结构图 app.run(port=2020,host="127.0.0.1",debug=True)
保存好几个文件后,从main.py中执行启动服务,在浏览器地址栏里可以顺利浏览本案例实现的网站,这已经测试正常通过。<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>{% block title %}Title {% endblock %} </title></head><body> {% block header %} <div>header</div> {% endblock %} {% block container %} <div>content</div> {% endblock %} {% block footer %} <div>made by Dr.Cao</div> {% endblock %}</body></html>
如代码中,使用了{% block header %}--{% endblock %}这样的代码对,中间放置对应页面区域的html代码,如在common.html中将页面整体划分了三个区域,header、container和footer。假设网站的每个网页都拥有相同的header和footer部分,就可以在common.html中将这两部分内容设计好。如果需要修改,就直接修改这个文件即可,别的网页就会即时响应变化。container主体内容部分肯定是每个页面都是不一样的。{% extends 'common.html' %} #导入模板文件{% block title %}产品页面 {% endblock %} #修改模板中的网页标题内容部分
保存好所有文件,重启main.py服务器文件,然后打开浏览器,在地址栏输入: http://127.0.0.1/product,其内容显示如下:<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>{% block title %}Title {% endblock %} </title> <style> .header,.footer{height:35px;width:100%;margin:0 auto;background:#333;color:#f0f0f0;} .header li{list-style:none;display:inline;width:300px;margin:0px 20px;} .container{height:100px;width:100%;border:1px solid #f30;} .footer{font-size:12px;text-align:center;height:20px;} </style></head><body> {% block header %} <div class="header"> #头部区域的导航 <ul> <li>首页</li> <li>最近新闻</li> <li>最新产品</li> <li>人力需求</li> <li>联系我们</li> </ul> </div> {% endblock %} {% block container %} #中部内容块区域 <div class="container">中部业务内容</div> {% endblock %} {% block footer %} #底部区域 <div class="footer"> Made by PeterCao,2020.联系方式:caoln2003@126.com </div> {% endblock %}</body></html>
然后再来浏览产品页,效果就变成了: