虚拟环境
什么是虚拟环境
它是一个虚拟化,从电脑独立开辟出来的环境。通俗的来讲,虚拟环境就是借助虚拟机docker来把一部分内容独立出来,我们把这部分独立出来的东西称作“容器”,在这个容器中,我们可以只安装我们需要的依赖包,各个容器之间互相隔离,互不影响。
为什么要用虚拟环境
在实际项目开发中,我们通常会根据自己的需求去下载各种相应的框架库,如Scrapy、Beautiful Soup等,但是可能每个项目使用的框架库并不一样,或使用框架的版本不一样,这样需要我们根据需求不断的更新或卸载相应的库。直接怼我们的Python环境操作会让我们的开发环境和项目造成很多不必要的麻烦,管理也相当混乱。
例如:,两个项目,项目A和项目B,一个用flask 1.0,一个用falsk 1.1,当分别使用两份项目的时候,要通过卸载安装去切换flask版本,很不方便,而虚拟环境可以很好的解决这个问题。
pipenv
这里介绍1中虚拟环境工具
pip install pipenv
进入/退出/删除虚拟环境
pipenv shell # 进入虚拟环境
exit # 退出虚拟环境
pipenv --rm # 删除整个环境 不会删除pipfile
pipfile
环境创建完后,当前目录下会有一个pipfile文件
cat pipfile
url # 指定国内pip源,不然下载库会很慢
dev-packages # 开发环境
packages # 生产环境
django = "*" # *表示最新版本
requires # Python版本
Flask
简介
flask是一款非常流行的Python Web框架,出生于2010年,作者是Armin Ronacher,本来这个项目只是作者在愚人节的一个玩笑,后来由于非常受欢迎,进而成为一个正式的项目。
flask自2010年发布第一个版本以来,大受欢迎,深得开发者的喜爱,并且在多个公司已经得到了应用,flask能如此流行的原因,可以分为以下几点:
- 微框架、简洁、只做他需要做的,给开发者提供了很大的扩展性。
- Flask和相应的插件写得很好,用起来很爽。
- 开发效率非常高,比如使用SQLAlchemy的ORM操作数据库可以节省开发者大量书写sql的时间。
Flask的灵活度非常之高,他不会帮你做太多的决策,一些你都可以按照自己的意愿进行更改。
Hello Flask
from flask import Flask
# 传入__name__初始化一个flask实例
app = Flask(__name__)
# app.route装饰器映射URL和执行的函数,这个设置将根URL映射到了hello函数上
@app.route('/hello/')
def hello():
return 'hello flask'
if __name__ == "__main__":
# 运行该项目,并将debug模式开启,默认网址是入http://127.0.0.1:5000,5000是端口号,可以更改
app.run(host='0.0.0.0', port=5000, debug=True)
然后点击运行,在浏览器中输入http://127.0.0.1:5000就能看到hello world了。需要说明一点的是,app.run这种方式只适合于开发,如果在生产环境中,应该使用Gunicorn或者uWSGI来启动。如果是在终端运行的,可以按ctrl+c来让服务停止。
项目配置
设置dubug模式
开启debug模式除了上面的方式还有:
# 第一种
app.debug = True
app.run
# 第二种,添加项目配置文件config.py,
# 推荐使用该种方式,一般项目会有很多配置项,全部写在该文件中即可
# 配置文件中
DEBUG = True
# flask文件中
import config
app.config.from_object(config)
方法还有很多,就不一一介绍了
需要注意的是,只能在开发环境下开启DEBUG模式,因为DEBUG模式会带来非常大的安全隐患。
另外,在开启了DEBUG模式后,当程序有异常而进入错误堆栈模式,你第一次点击某个堆栈想查看变量值的时候,页面会弹出一个对话框,让你输入PIN值,这个PIN值在你启动的时候就会出现,比如在刚刚启动的项目中的PIN值为294-745-044(项目启动后编辑器终端命令中有),你输入这个值后,Werkzeug会把这个PIN值作为cookie的一部分保存起来,并在8小时候过期,8小时以内不需要再输入PIN值。这样做的目的是为了更加的安全,让调试模式下的攻击者更难攻击到本站。
URL与函数的映射
@app.route装饰器中,可以指定URL的规则来进行更加详细的映射,比如现在要映射一个文章详情的URL,文章详情的URL是/article/id/,id有可能为1、2、3…,那么可以通过以下方式
# 带有参数的url
@app.route('/article/<int:id>')
def article(id):
return f'article: {id}'
其中,尖括号是固定写法,语法为,variable默认的数据类型是字符串。如果需要指定类型,则要写成converter:variable,其中converter就是类型名称,可以有以下几种:
- string: 默认的数据类型,接受没有任何斜杠/的字符串。
- int: 整形
- float: 浮点型。
- path: 和string类似,但是可以传递斜杠/。
- uuid: uuid类型的字符串。
- any:可以指定多种路径
# 获取?bid=xxxx上传的参数,需从flask中导入request
@app.route('/book/')
def book():
bid = request.args.get('bid')
print(f'我在这里: {bid}')
return 'ohhhhh'
结果:
我在这里: lalala
如果不想定制子路径来传递参数,也可以通过传统的?=的形式来传递参数,例如:/article?id=xxx,这种情况下,可以通过request.args.get(‘id’)来获取id的值。如果是post方法,则可以通过request.form.get(‘id’)来进行获取。
构造URL(url_for)
url_for()函数接收两个及以上的参数,第一个参数是对应的函数名,如果还有其他参数,则会添加到url后作为查询参数。
使用url_for的好处
- 将来如果修改了URL,但没有修改该URL对应的函数名,就不用到处去替换URL了。
- url_for()函数会转义一些特殊字符和unicode字符串,这些事情url_for会自动的帮我们搞定
@app.route('/article/<int:id>')
def article(id):
return f'article: {id}'
@app.route('/')
def home():
print(url_for('article', id=1))
return 'home'
指定HTTP方法
在@app.route()中可以传入一个关键字参数methods来指定本方法支持的HTTP方法,默认情况下,只能使用GET请求
@app.route('/login/',methods=['GET','POST'])
def login():
return 'login'
以上装饰器将让login的URL既能支持GET又能支持POST
页面跳转和重定向
重定向分为永久性重定向和暂时性重定向,在页面上体现的操作就是浏览器会从一个页面自动跳转到另外一个页面。比如用户访问了一个需要权限的页面,但是该用户当前并没有登录,因此我们应该给他重定向到登录页面。
- 永久性重定向:http的状态码是301,多用于旧网址被废弃了要转到一个新的网址确保用户的访问,最经典的就是京东网站,你输入www.jingdong.com的时候,会被重定向到www.jd.com,因为jingdong.com这个网址已经被废弃了,被改成jd.com,所以这种情况下应该用永久重定向。
- 暂时性重定向:http的状态码是302,表示页面的暂时性跳转。比如访问一个需要权限的网址,如果当前用户没有登录,应该重定向到登录页面,这种情况下,应该用暂时性重定向。
在flask中,重定向是通过flask.redirect(location,code=302)这个函数来实现的,location表示需要重定向到的URL,应该配合之前讲的url_for()函数来使用,code表示采用哪个重定向,默认是302也即暂时性重定向,可以修改成301来实现永久性重定向。
from flask import Flask,url_for,redirect
app = Flask(__name__)
@app.route('/login/',methods=['GET','POST'])
def login():
return 'login'
@app.route('/profile/',methods=['GET','POST'])
def profile():
name = request.args.get('name')
if not name:
return redirect(url_for('login'))
else:
return name
Response
视图函数中可以返回以下类型的值:
- Response对象。
- 字符串。其实Flask是根据返回的字符串类型,重新创建一个werkzeug.wrappers.Response对象,Response将该字符串作为主体,状态码为200,MIME类型为text/html,然后返回该Response对象。
- 元组。元组中格式是(response,status,headers)。response为一个字符串,status值是状态码,headers是一些响应头。
- 如果不是以上三种类型。那么Flask会通过Response.force_type(rv,request.environ)转换为一个请求对象。
直接使用Response创建
from werkzeug.wrappers import Response
@app.route('/about/')
def about():
resp = Response(response='about page',status=200,content_type='text/html;charset=utf-8')
return resp
可以使用make_response函数来创建Response对象,这个方法可以设置额外的数据,比如设置cookie,header信息
from flask import make_response
@app.route('/about1/')
def about():
return make_response('about page')
通过返回元组的形式
@app.errorhandler(404)
def not_found():
return 'not found',404
完整代码如下
from flask import Flask, request, url_for, redirect, make_response
import config
from werkzeug.wrappers import Response
# 传入__name__初始化一个flask实例
app = Flask(__name__)
app.config.from_object(config)
# app.route装饰器映射URL和执行的函数,这个设置将根URL映射到了hello函数上
@app.route('/hello/')
def hello():
return 'hello flask'
# 带有参数的url
@app.route('/article/<int:id>')
def article(id):
return f'article: {id}'
# 获取?bid=xxxx上传的参数
@app.route('/book/')
def book():
bid = request.args.get('bid')
print(f'我在这里: {bid}')
return 'ohhhhh'
@app.route('/')
def home():
print(url_for('article', id=1))
return 'home'
@app.route('/login/',methods=['GET','POST'])
def login():
return 'login'
@app.route('/profile/',methods=['GET','POST'])
def profile():
name = request.args.get('name')
if not name:
return redirect(url_for('login'))
else:
return name
@app.route('/about/')
def about():
resp = Response(response='about page',status=200,content_type='text/html;charset=utf-8')
return resp
@app.route('/about1/')
def about1():
return make_response('about page')
@app.errorhandler(404)
def not_found(error):
return 'not found',404
if __name__ == "__main__":
# 运行该项目,并将debug模式开启,默认网址是入http://127.0.0.1:5000,5000是端口号,可以更改
app.run(host='127.0.0.1', port=5000, debug=True)