Flask 没有限定使用哪一种数据库,无论是 SQL 仍是 NoSQL。若是你不想本身编写负责的 SQL语句的话,你也可使用 ORM
,经过 SQLALchemy
便可实现。css
安装html
pip install flask-sqlalchemy # 要链接mysql数据库,仍须要安装flask-mysqldb pip install flask-mysqldb # 或者你还还需 pymyql pip3 install pymyql
相关网站:python
Flask-SQLAlchemy 数据库 URLmysql
# hostname:主机、database:数据库,username、password 数据库用户名和密码 # mysql mysql://username:password@hostname/database # postgres postgresql://username:password@hostname/database # SQLite unix sqlite:////absolute/path/to/database # sqlite windows sqlite:///c:/absolute/path/to/database
链接 MySQLjquery
from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) # 设置链接数据库的URL app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:xxx@localhost/t1' #设置每次请求结束后会自动提交数据库中的改动 app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True app.config['SQLALCHEMY_ECHO'] = True # 查询时会显示原始SQL语句 db = SQLAlchemy(app)
经常使用 sqlalchemy 列类型nginx
经常使用 sqlalchemy 列选项web
经常使用 SQLAlchemy 关系选项sql
无论是插入、修改、仍是删除操做,均由数据库会话管理,会话用 db.session
表示。数据库会话是为了保证数据的一致性,避免因部分更新致使数据不一致。提交操做把会话对象所有写入数据库,若是写入过程发生错误,整个会话都会失效。数据库会话也能够回滚,经过 db.session.rollback()
方法,实现会话提交数据前的状态。shell
建立、删除、插入数据库
# 建立表 # 若是表存在,则帮助从新建立或更新 # 若是要修改模型后要把应用到现有数据库中,这个操做不行,更新现有数据库的粗暴方式是先删除再建立 db.create_all() # 删除表 db.drop_all() # 插入一条数据 ro1 = Role(name='admin') db.session.add(ro1) db.session.commit() # 一次插入多条数据 us1 = User(name='wang',email='xxx@163.com',pswd='123456',role_id=ro1.id) us2 = User(name='zhang',email='xxx@189.com',pswd='201512',role_id=ro2.id) db.session.add_all([us1,us2]) db.session.commit()
查询
# 查询:filter_by精确查询 User.query.filter_by(name='wang').all() # first()返回查询到的第一个对象 User.query.first() # all()返回查询到的全部对象 User.query.all() # filter模糊查询,返回名字结尾字符为g的全部数据。 User.query.filter(User.name.endswith('g')).all() # get(),参数为主键,若是主键不存在没有返回内容 User.query.get() # 逻辑非,返回名字不等于wang的全部数据。 User.query.filter(User.name!='wang').all() # 逻辑与,须要导入and,返回and()条件知足的全部数据。 from sqlalchemy import and_ User.query.filter(and_(User.name!='wang',User.email.endswith('163.com'))).all() # 逻辑或,须要导入or_ from sqlalchemy import or_ User.query.filter(or_(User.name!='wang',User.email.endswith('163.com'))).all() # not_ 至关于取反 from sqlalchemy import not_ User.query.filter(not_(User.name=='chen')).all() # 查询数据后删除 user = User.query.first() db.session.delete(user) db.session.commit() User.query.all() # 关联查询示例:角色和用户的关系是一对多的关系,一个角色能够有多个用户,一个用户只能属于一个角色。 查询角色的全部用户: #查询roles表id为1的角色 ro1 = Role.query.get(1) #查询该角色的全部用户 ro1.us # 查询用户所属角色: #查询users表id为3的用户 us1 = User.query.get(3) #查询用户属于什么角色 us1.role
更新
# 更新数据 user = User.query.first() user.name = 'dong' db.session.commit() User.query.first() # 使用update User.query.filter_by(name='zhang').update({'name':'li'})
查看原生 SQL
>>> str(User.query.filter_by(role=user_role) ... ) 'SELECT users.id AS users_id, users.username AS users_username, users.role_id AS users_role_id \nFROM users \nWHERE %( param_1)s = users.role_id'
经常使用 sqlAlchemy 查询过滤器
经常使用 SQLAlchemy 查询执行函数
示例:在视图函数中定义模型类
from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) #设置链接数据库的URL app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:mysql@127.0.0.1:3306/Flask_test' #设置每次请求结束后会自动提交数据库中的改动 app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True # 查询时会显示原始SQL语句 app.config['SQLALCHEMY_ECHO'] = True db = SQLAlchemy(app) class Role(db.Model): # 定义表名 __tablename__ = 'roles' # 定义列对象 id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(64), unique=True) us = db.relationship('User', backref='role') #repr()方法显示一个可读字符串 def __repr__(self): return 'Role:%s'% self.name class User(db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(64), unique=True, index=True) email = db.Column(db.String(64),unique=True) pswd = db.Column(db.String(64)) role_id = db.Column(db.Integer, db.ForeignKey('roles.id')) def __repr__(self): return 'User:%s'%self.name if __name__ == '__main__': db.drop_all() db.create_all() ro1 = Role(name='admin') ro2 = Role(name='user') db.session.add_all([ro1,ro2]) db.session.commit() us1 = User(name='rose',email='rose@163.com',pswd='123',role_id=ro1.id) us2 = User(name='lila',email='lila@189.com',pswd='456',role_id=ro2.id) us3 = User(name='john',email='john@126.com',pswd='789',role_id=ro2.id) db.session.add_all([us1,us2,us3]) db.session.commit() app.run(debug=True)
开发时,须要修改数据库模型,修改以后要更新数据库。表不存在时就建立,存在时,更新表的惟一方式是先删除后建立,可是会丢失数据。
更新表的最好方式是使用 数据库迁移框架,Flask 使用的是 Alembic
(https://alembic.readthedocs.org/en/latest/index.html),集成在 Flask-Script
中:
# pip3 install flask-migrate from flask_migrate import Migrate, MigrateCommand app = Flask(__name__) manager = Manager(app) app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:xxxx@localhost/t1' app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True db = SQLAlchemy(app) migrate = Migrate(app, db) # 第一个参数是Flask的实例,第二个参数是Sqlalchemy数据库实例 manager.add_command('db', MigrateCommand) # 这条语句在flask-Script中添加一个db命令
初始化数据库
在维护数据库迁移以前,使用 init
子命令建立迁移仓库:
此时你会看到项目中生成一个 migrations
的文件夹,全部迁移脚本都存放其中。
建立迁移脚本
Alembic 中,迁移脚本中有两个函数:upgrade()
he downgrade()
:
upgrade()
:把迁移中改动应用到数据库中upgrade()
:将改动删除revision
命令手动建立 Alembic 迁移,migrate
自动建立(自动建立可能会有错误,必定要检查下),自动建立迁移脚本:
发现出现:too many arguments
错误,用 python3 s1.py db migrate --help
命令查看 migrate
命令后面到底能够接什么参数,发现 -m
是能够的,但为何会报错呢 ?
尝试不输入 'initial migration'
那么长,而是随便输入了一个 's'
,发现居然成功了:
数据回滚
若是要回滚,那么首先要指定版本号,查看版本号:
# 因为版本号是随机字符串,为避免出错,建议先使用 history 命令查看历史版本的具体版本号,而后复制具体版本号执行回退。 python database.py db history # 回滚 python database.py db downgrade 版本号
在这里咱们将建立一个简单的可以添加书籍的小程序,整个项目结构以下图所示:
一、定义模型,models.py
:
from flask_test.s4 import db class Author(db.Model): """定义模型类-做者""" __tablename__ = 'author' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(32), unique=True) email = db.Column(db.String(64)) au_book = db.relationship('Book', backref='author', lazy='dynamic') def __str__(self): return 'Author:%s' % self.name class Book(db.Model): """定义模型类-书名""" __tablename__ = 'books' id = db.Column(db.Integer, primary_key=True) info = db.Column(db.String(32),unique=True) leader = db.Column(db.String(32)) au_book = db.Column(db.Integer, db.ForeignKey('author.id')) def __str__(self): return 'Book:%s' % self.info
二、定义 Form 表单,my_forms.py
:
from flask_wtf import FlaskForm from wtforms.validators import DataRequired from wtforms import StringField, SubmitField class Append(FlaskForm): """添加信息""" auth_info = StringField(label='做者', validators=[DataRequired()]) book_info = StringField(label='书名', validators=[DataRequired()]) submit = SubmitField(u'添加')
三、主程序,app.py
:
from flask import Flask, render_template, redirect, url_for, request from flask_test.my_extend import models from flask_test.my_extend.my_forms import Append from flask_script import Manager from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) manager = Manager(app) #设置链接数据 app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:password@localhost/t2' #设置每次请求结束后会自动提交数据库中的改动 app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True #设置成 True,SQLAlchemy 将会追踪对象的修改而且发送信号。这须要额外的内存, 若是没必要要的能够禁用它。 app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True app.config['SECRET_KEY'] = 's' #实例化SQLAlchemy对象 db = SQLAlchemy(app) @app.route('/', methods=['GET', 'POST']) def index(): # 查询全部做者和书名信息 author_list = models.Author.query.all() book_list = models.Book.query.all() return render_template('info.html', author_list=author_list, book_list=book_list) @app.route('/add_book', methods=['GET', 'POST']) def add_book(): """添加书籍""" form = Append() # 建立表单对象 if form.validate_on_submit(): # 获取表单输入数据 wtf_auth = form.auth_info.data wtf_book = form.book_info.data print(wtf_book, wtf_auth) # 将表单输入的数据存入到模型中 db_auth = models.Author(name=wtf_auth) db_book = models.Book(info=wtf_book) # 提交会话 db.session.add_all([db_auth, db_book]) db.session.commit() return redirect(url_for('index')) else: if request.method == 'GET': return render_template('add_book.html', form=form) if __name__ == '__main__': manager.run()
四、info.html
```python <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.css') }}"> </head> <body> <div class="col-md-6" style="margin-left: 100px"> <h1>玄幻系列</h1> <button class="btn pull-right" style="margin-bottom: 15px;"><a href="/add_book">添加</a> </button> <table class="table table-striped table-bordered"> <thead> <tr> <th>做者</th> <th>书名</th> </tr> </thead> <tbody> <tr> {% for author in author_list %} <td>{{ author.name }}</td> {% endfor %} {% for book in book_list %} <td>{{ book.info }}</td> {% endfor %} </tr> </tbody> </table> </div> <script src="{{ url_for('static', filename='js/jquery-3.1.1.js') }}"></script> <script src="{{ url_for('static', filename='js/bootstrap.js') }}"></script> </body> </html>
五、add_book.html
:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/add_book" method="post"> {{ form.csrf_token }} <p>{{ form.auth_info.label }} {{ form.auth_info }}</p> <p>{{ form.book_info.label }} {{ form.book_info }}</p> <p>{{ form.submit }}</p> </form> </body> </html>
效果图以下:
flask 不能进入 shell
flask 进入 shell,命令:python 程序文件.py shell
要安装:pip3 install flask-script
,程序中使用:
from flask_script import Manager from flask import Flask app = Flask(__name__) manager = Manager(app) if __name__ == '__main__': manager.run()
flask 在链接MySQL出现ModuleNotFoundError: No module named 'MySQLdb'错误
解决办法:只要在配置 SQLALCHEMY_DATABASE_URI
时,加上一个 pymysql
就能够了:
# 记得安装 pymysql app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:dzd123@localhost/你的数据库名'
参考文章:https://blog.csdn.net/qq_25046261/article/details/78991442
进入 shell 时出现错误:SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and '
解决办法:
# 修改 flask_sqlalchemy 的 __init__.py # 查找方法:在程序中导入 flask_sqlalchemy,按住 Ctrl 键,鼠标点击 flask_sqlalchemy,就会定位到 __init__.py 中,而后 Ctrl + F 查找 track_modifications 便可 # 在init.py里面有 init_app方法,修改下面的一行 track_modifications = app.config.setdefault('SQLALCHEMY_TRACK_MODIFICATIONS', True)
参考文章:https://blog.csdn.net/qq_25730711/article/details/53690687
Flask 的扩展包 Flask-Mail
经过包装了 Python
内置的 smtplib
包,能够用在Flask
程序中发送邮件。
Flask-Mail
链接到简单邮件协议(Simple Mail Transfer Protocol,SMTP
)服务器,并把邮件交给服务器发送。
示例:下面以 qq 邮箱为示例演示下如何在 Flask 程序中发送邮件
一、开启 IMAP/SMTP
服务,生成受权码:
二、app.py
pip3 install flask_mail ``` ```python from flask import Flask from flask_mail import Mail, Message app = Flask(__name__) # 配置邮件:服务器/端口/传输层安全协议/邮箱名/密码 app.config.update( DEBUG = True, MAIL_SERVER='smtp.qq.com', MAIL_PROT=465, MAIL_USE_TLS=True, MAIL_USERNAME='98xxx616@qq.com', MAIL_PASSWORD='vnpyuevrhqyybccd', # 受权码 ) mail = Mail(app) @app.route('/') def index(): # sender 发送方,recipients 接收方列表,This is a test 为邮件标题 msg = Message("This is a test ", sender='9825xx616@qq.com', recipients=['146xx0@qq.com', 'junxx@outlook.com']) #邮件内容 msg.body = "Flask 邮件测试" #发送邮件 mail.send(msg) print("邮件发送中...") return "发生成功!" if __name__ == "__main__": app.run()
运行程序,访问:http://127.0.0.1:5000/
:
一个项目有不少的页面(视图),也就意味着会有不少路由,若是把全部代码写在一个文件中(启动文件、路由、配置等等),显然程序变得模块化,耦合性太差,后期维护过于困难。
采用 Python 模块导入的方式将程序拆分红多个文件,虽然下降程序耦合,可是也不能解决路由映射问题。Flask 提倡使用蓝图解决此类问题。那么什么是蓝图呢?
蓝图是用于实现单个应用的视图、模板、静态文件的集合,是模块化处理的类。简单来讲,蓝图就是一个存储操做路由映射方法的容器,主要用来实现客户端请求和URL相互关联的功能。 在Flask中,使用蓝图能够帮助咱们实现模块化应用的功能。
蓝图使用
1、建立蓝图对象。 #Blueprint必须指定两个参数,admin表示蓝图的名称,__name__表示蓝图所在模块 admin = Blueprint('admin',__name__) 2、注册蓝图路由。 @admin.route('/') def admin_index(): return 'admin_index' 3、在程序实例中注册该蓝图。 app.register_blueprint(admin,url_prefix='/admin')
示例:
三个程序文件:login.py、user.py、manage.py
,至关于三个 app,其中 manage.py
做为主要程序文件(启动问)。
实现目标:在主程序与子程序中定义相同的路由 URL,可以同时访问,互不影响。
项目结构:
user.py
from flask import Blueprint,render_template users = Blueprint('user',__name__) @users.route('/user') def user(): return render_template('user.html')
login.py
from flask import Blueprint,render_template #建立蓝图 logins = Blueprint('login',__name__) @logins.route('/login') def login(): return render_template('login.html')
manage.py
from flask import Flask #导入蓝图对象 from login import logins from user import users app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello World!' @app.route('/login') def sss(): return 'login' #注册蓝图,第一个参数logins是蓝图对象,url_prefix参数默认值是根路由,若是指定,会在蓝图注册的路由url中添加前缀。 app.register_blueprint(logins, url_prefix='/ll') app.register_blueprint(users, url_prefix='') if __name__ == '__main__': app.run(debug=True)
在蓝图 login.py
中 login()
函数的路由咱们使用了:/login
,主程序 manage.py
中 sss()
函数也使用了 /login
若是蓝图 logins
没有指定 url_prefix=''
路由前缀,那么访问:http://127.0.0.1:5000/login
获得的会是函数 sss()
所渲染的值。
那么访问蓝图 logins
,应该使用:http://127.0.0.1:5000/ll/login
动态路由
login.py
@logins.route('/login/<id>') def login(id): print(id) return render_template('login.html')
访问:http://127.0.0.1:5000/ll/login/2
Web程序开发过程通常包括如下几个阶段:需求分析,设计阶段,实现阶段,测试阶段。其中测试阶段经过人工或自动来运行测试某个系统的功能。目的是检验其是否知足需求,并得出特定的结果,以达到弄清楚预期结果和实际结果之间的差异的最终目的。
测试的分类:
测试从软件开发过程能够分为:单元测试、集成测试、系统测试等。在众多的测试中,与程序开发人员最密切的就是单元测试,由于单元测试是由开发人员进行的,而其余测试都由专业的测试人员来完成。因此咱们主要学习单元测试。
什么是单元测试?
程序开发过程当中,写代码是为了实现需求。当咱们的代码经过了编译,只是说明它的语法正确,功能可否实现则不能保证。 所以,当咱们的某些功能代码完成后,为了检验其是否知足程序的需求。能够经过编写测试代码,模拟程序运行的过程,检验功能代码是否符合预期。
单元测试就是开发者编写一小段代码,检验目标代码的功能是否符合预期。一般状况下,单元测试主要面向一些功能单一的模块进行。在Web开发过程当中,单元测试实际上就是一些“断言”(assert)代码。
断言就是判断一个函数或对象的一个方法所产生的结果是否符合你指望的那个结果。 python中assert断言是声明布尔值为真的断定,若是表达式为假会发生异常。单元测试中,通常使用assert来断言结果。
断言使用:
>>> a = [1, 2, 3, 4] >>> b = 2 >>> assert b in a # 为真则经过 >>> assert b not in a # 为假则报错 Traceback (most recent call last): File "<stdin>", line 1, in <module> AssertionError # 自定义异常 >>> assert b not in a, 'False' Traceback (most recent call last): File "<stdin>", line 1, in <module> AssertionError: False
经常使用的断言方法:
assertEqual # 若是两个值相等,则pass assertNotEqual # 若是两个值不相等,则pass assertTrue # 判断bool值为True,则pass assertFalse # 判断bool值为False,则pass assertIsNone # 不存在,则pass assertIsNotNone # 存在,则pass
简单测试用例:
>>> def add(x, y): ... return x + y ... >>> assert add(2, 3) == 5 >>> assert add(2, 3) == 6, 'False' Traceback (most recent call last): File "<stdin>", line 1, in <module> AssertionError: False
单元测试的基本写法:
测试基本框架:
import unittest class TestClass(unittest.TestCase): def setUp(self): """该方法会首先执行,方法名为固定写法""" pass def tearDown(self): """该方法会在测试代码执行完后执行,方法名为固定写法""" pass def test_app_exists(self): """测试代码""" pass
在 setUp()
方法的代码建立了一个新的测试客户端而且初始化了一个新的数据库。这个函数将会在每次独立的测试函数运行以前运行。要在测试以后删除这个数据库,咱们在 tearDown()
函数当中关闭这个文件,并将它从文件系统中删除。同时,在初始化的时候 TESTING
配置标志被激活,这将会使得处理请求时的错误捕捉失效,以便于您在进行对应用发出请求的测试时得到更好的错误反馈。
一、测试响应内容是否与预期一致
def test_index(self): resp = self.client.get('/') print(resp.data) self.assertEqual(resp.data, b'Hello World!')
二、测试登录和登出
咱们应用的大部分功能只容许具备管理员资格的用户访问。因此咱们须要一种方法来帮助咱们的测试客户端登录和登出。为此,咱们向登录和登出页面发送一些请求,这些请求都携带了表单数据(用户名和密码),由于登录和登出页面都会重定向,咱们将客户端设置为 follow_redirects
。
def login(self, username, password): return self.app.post('/login', data=dict( username=username, password=password ), follow_redirects=True) def logout(self): return self.app.get('/logout', follow_redirects=True) def test_login_logout(self): rv = self.login('admin', 'default') assert 'You were logged in' in rv.data rv = self.logout() assert 'You were logged out' in rv.data rv = self.login('adminx', 'default') assert 'Invalid username' in rv.data rv = self.login('admin', 'defaultx') assert 'Invalid password' in rv.data
三、数据库测试
import unittest from author_book import * #自定义测试类,setUp方法和tearDown方法会分别在测试先后执行。以test_开头的函数就是具体的测试代码。 class DatabaseTest(unittest.TestCase): def setUp(self): app.config['TESTING'] = True app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:mysql@localhost/test0' self.app = app db.create_all() def tearDown(self): db.session.remove() db.drop_all() #测试代码 def test_append_data(self): au = Author(name='itcast') bk = Book(info='python') db.session.add_all([au,bk]) db.session.commit() author = Author.query.filter_by(name='itcast').first() book = Book.query.filter_by(info='python').first() #断言数据存在 self.assertIsNotNone(author) self.assertIsNotNone(book)
一直以来咱们都是使用的 flask
自带的服务器,完成了web服务的启动。在生产环境中,flask 自带的服务器,没法知足性能要求。
这里采用 Gunicorn
作 wsgi
容器,来部署 flask
程序。Gunicorn
(绿色独角兽)是一个Python WSGI
的HTTP
服务器。从Ruby
的独角兽(Unicorn
)项目移植。该 Gunicorn
服务器与各类Web框架兼容,实现很是简单,轻量级的资源消耗。Gunicorn
直接用命令启动,不须要编写配置文件,相对 uWSGI
要容易不少。
几个概念:
Web Server Gateway Interface
(web服务器网关接口),它是一种规范,它是web
服务器和 web
应用程序之间的接口。它的做用就像是桥梁,链接在 ` 服务器和
web`应用框架之间。uwsgi
协议WSGI
的web
服务器。在这里咱们采用 nginx + gunicorn + flask
方式部署 flask,你也能够采用别的方式,好比:Django(uWSGI+Nginx)等等,只不过 gunicorn
相对来讲更简单操做一些。
正向代理及反向代理
代理种类 | 说明 | 特色 | |
---|---|---|---|
正向代理 | 请求通过代理服务器从局域网发出,而后到达互联网上的服务器 | 服务端并不知道真正的客户端是谁 | 客户端 |
反向代理 | 请求从互联网发出,先进入代理服务器,再转发给局域网内的服务器 | 客户端并不知道真正的服务端是谁 | 服务端 |
使用 Nginx 的优点:
经常使用命令
# 安装 $ pip3 install gunicorn # 查看命令行选项: $ gunicorn -h # 直接运行,默认启动的 127.0.0.1::8000 gunicorn 运行文件名称:Flask程序实例名 # 示例 gunicorn s2:app # 指定进程和端口号: -w: 表示进程(worker)。 -b:表示绑定ip地址和端口号(bind)。 $ gunicorn -w 4 -b 127.0.0.1:5001 运行文件名称:Flask程序实例名
踩坑
运行 gunicorn
时发生以下错误:
# 错误 gunicorn.errors.HaltSever:<HaltServer 'Worker faild to boot.' 3
使用 debug
模式查看更多信息--log-level=debug
,也能够在后边加上参数 –preload
,即可看到详细的报错信息:
gunicorn -w 4 -b 192.168.21.128:5001 s2:app --log-level=debug
发现是 import error
,错误提醒说 s2.py
不是个包文件,这是 Python import 的问题。
解决方法
一、给这个执行文件添加环境变量
# 添加环境变量 vim /etc/profile export PATH="$PATH:/home/hj/桌面/fk" # 将路径设置你的执行文件路径(在 profile 文件最后添加) # 关闭保存 profile 文件 source /etc/profile # 测试下有没有添加成功 echo $PATH
二、将这个执行文件变为包文件
# 在 fk 文件夹中新建一个 __init__.py 文件便可 vim __init__.py hj@hj:~/桌面/fk$ ls error.log __init__.py __pycache__ s s2.py
三、再运行:gunicorn -w 4 -b 192.168.21.128:5001 s2:app
,发现成功了:
参考文章:gunicorn启动报错gunicorn.errors.HaltServer
安装 Nginx
$ sudo apt-get install nginx
Nginx 经常使用命令
Ubuntu 中你能够像任何其余 systemd 单位同样管理 Nginx 服务:
# 中止Nginx服务 sudo systemctl stop nginx # 再次启动 sudo systemctl start nginx # 从新启动Nginx服务: sudo systemctl restart nginx # 在进行一些配置更改后从新加载 Nginx 服务: $sudo systemctl reload nginx # 若是你想禁用Nginx服务在启动时启动: $sudo systemctl disable nginx # 并从新启用它: $sudo systemctl enable nginx # 查看 ps -ef | grep nginx
Nginx 配置
一、为 Nginx 添加配置文件,Ngnix 默认配置文件加载是在 /etc/nginx/conf.d/
目录下,新建一个配置文件(名字随意),编辑以下:
server { # 监听80端口 listen 80; # 本机 server_name 192.168.21.128; # 默认请求的url location / { # 请求转发到gunicorn服务器 proxy_pass http://127.0.0.1:5001; # 设置请求头,并将头信息传递给服务器端 proxy_set_header Host $host; } }
二、启动 Nginx 服务 /etc/init.d/nginx start
,访问:http://192.168.21.128:5001/
,效果以下图:
总结
gunicorn
服务器server_name
要和 gunicorn
启动的 -b
参数地址一致