Flask学习笔记

区别

flask 轻量级 买房等于买一个毛坯房,什么都要自己弄
django 重量级 买房相当于一个精装修的,但是你不一定会用

mvc: a) Model层:根据业务需求,来封装数据库操作,用于操作相应数据 b) controller层:接收请求,处理业务,返回响应(HTML、JSON、其他) c) view层:由控制层发起模块页面的填充调用

虚拟环境

  1. 安装虚拟环境
pip install virtulenv
  1. 下载虚拟环境管理工具,python安装路径不能有中文路径
pip install virtulenvwrapper-win(windows版)
  1. 创建虚拟环境
  2. 虚拟环境操作
进入虚拟环境:  workon 环境名
退出虚拟环境:  deactivate
删除虚拟环境:  rmvirtualenv 环境名
列出虚拟环境:  lsvirtualenv
进入虚拟环境目录:   cdvirtualenv  环境名
查看安装包:     pip list

一、flask简介

官网:https://flask.palletsprojects.com/en/2.2.x/
中文学习文档:https://dormousehole.readthedocs.io/en/latest/

  1. 使用pycharm专业版,可以直接生成flask的框架,专业版的激活码可以上公众号“python联盟”回复“激活码”
  2. pycharm的community版本,查看文档“python前后端.md”

二、入门

配置讲解


app.py

from flask import Flask

# 使用Flask创建一个app对象,并且传递__name__参数
app = Flask(__name__)

# @app.route,设置访问的url,这里是设置成一个根路径
@app.route('/')
def hello_world():  # put application's code here
    return 'Hello World!'


if __name__ == '__main__':
    app.run(debug=True,port=5001)

注意:pycharm的debug或者其他配置未生效,见csdn的flask收藏夹

url和视图

  • 返回json格式的字符串
from flask import jsonify
  • 视图转url
from flask import url_for
  • 指定url

  • 指定method
    在@app.route上,添加method参数,这个参数是一个列表类型,可以传递多个

  • 重定向
    redirect

模板

  1. 模板文件,也就是html文件,需要放到templates文件夹下,当然在 Flask(__name__,template_folder)可以修改模板的地址,一般不修改
  2. 通过来渲染模板
from flask import render_template
  1. 可以通过定义为字典来传递变量,通过关键字参数传递

蓝图

from flask import Blueprint

mysql数据库

  1. SQLAlchemy:是一个独立的ORM框架,可以独立于Flask存在,也可以在其他项目中使用
  2. Flask-SQLAlchemy:对SQLAlchemy的一个封装,能够更适合在flask中使用
  • 安装
pip install pymysql
pip install Flask-SQLAlchemy
  • 连接数据库
HOSTNAME = '127.0.0.1'
PORT     = '3306'
DATABASE = 'xt_flask'
USERNAME = 'root'
PASSWORD = 'root'
DB_URI = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNAME,PASSWORD,HOSTNAME,PORT,DATABASE)
  • 增删改查
    #1. 添加数据
    # article= Article(title="英语",content="XX")
    # ad.session.add(article)
    # db.session.commit()
    # return "数据操作成功"
    # #2. 查询数据
    # #filter_by:返回一个类列表的对象
    # article= Article.query.filter_by(id=1)[0]
    # print(article.title)
    # return "数据操作成功"
    # #3. 修改数据
    # article= Article.query.filter_by(id=1)[0]
    # article.content="yyy"
    # db.session.commit()
    # return "数据操作成功"
    # #4. 删除数据
    # article= Article.query.filter_by(id=1).delete()
    # db.session.commit()
    return "数据操作成功"

迁移migrate

  • ModuleNotFoundError: No module named ‘flask_mail’ 错误解决
    使用pip3 再安装一遍
    terminal操作
1. flask db init                      #初始化
2. flask db migrate  -m "修改的信息"   #提交类似于commit
3. flask db upgrade  #更新到数据库     #类似于push

邮件

pip install flask-Mail
@bp.route("/mail")
def senf_mail():
    message=Message(
        subject="邮箱测试",
        recipients=["409788696@qq.com"],
        body="这是测试邮件",
        sender="maohui@well-healthcare.com"
    )
    mail.send(message)
    return "success"

CORS跨域问题

from flask_cors import CORS
CORS(app,supports_credentials=True)  #解决跨域问题

部署flask项目

1. docker search python
2. docker pull python:3.10
3. docker run -uroot -it -p 3344:5000 python:3.10 /bin/bash
4. pip freeze > requirements.txt
5. 

将项目文件移到linux中
6. 见mysql笔记,另外搭建一个MySQL的linux独立docker 镜像环境(root:123456)
7. aiyun开放mysql端口安全组
8. 安装git,并clone下项目文件
9. pip install -r requirements.txt(解决pip源太慢,sudo pip config set global.index-url https://pypi.doubanio.com/simple)
**注意此时用的是一个python自带的开发者服务器,无法支持生产环境的并发,所以需要用到nginx服务器**

nginx介绍

官网:http://nginx.org/
中文资料:http://www.nginx.cn/doc/index.html
http://tengine.taobao.org/book/

简介

  1. 轻量级
  2. 并发能力强 最高50000
  3. 高度模块化
  4. 负载均衡
  5. 反向代理
    ·正向代理:

    ·反向代理:

    ·总结
  • 下载安装使用

下载安装使用

  1. 下载安装见官网
  2. ngnix控制
  3. 配置文件







uwsgi介绍

pip install uwsgi

部署

blog项目

环境

pip镜像

在当前登录用户的主目录下创建pip目录,并创建pip.ini文件,使用豆瓣网的python镜像,编辑文件为如下内容

[global]
index-url = http://pypi.doubanio.com/simple/
[install]
trusted-host = pypi.doubanio.com

需要安装的库

pip install 
pymysql
SQLAlchemy  #mysql的ORM库
jinja2  #flaskde mo模板引擎
Flask   #flask框架核心应用
flask-cors  #flask的跨域解决方案
redis      #Redis缓存服务器处理库
pillow     #python图像处理库
requests
jieba      #python中文分词库
Whoosh     #python用于创建倒排索引的库
blinker    #支持库,用于flask的对象通信
flask-msearch  #基于flask和sqlalchemy的全文搜索库

前端页面开发

  1. ui设计
  2. 绘制线框图
  3. 使用html实现线框图
  4. 填充页面内容
  5. 对内容进行微调

数据库开发设计

1.按照业务需求,设计表名和字段名
例如:

Flask框架基础

  1. 路由与参数

/
/int:args

参数必须作为函数的形参
def fun(args)
return f"{args}"

读取get的参数:
value=request.args.get("")
读取post的参数:
value=request.form.get("")
  1. RESTful

  1. 重定向
1)使用flask自带的
@app.route('/red')
def func():
    return redirect(url_for('index'))

2)使用js重定向

@app.route('/red')
def func():
    html = '感谢访问,2秒后将跳转到首页'
    html += "<script>"
    html += "setTimeout(function(){location.href='/'},2000);"
    html += "</script>"
    return html
  1. Session 和Cookie
    1)要处理session,则必须要为app实例设置SECRET_KEY配置参数,配置随机数生成器(Session ID),再使用session函数进行操作.
    2)要处理Cookie,需要使用response对象往HTTP的响应中写入满足HTTP协议的Cookie要求的信息(key,Value,Age)

设置session
@app.route('/session)
def sess():
    session['username'] = 'maohui'
    session['role'] = 'editor'
    return Done

设置cookie
@app.route('/cookie)
def cookie():
    response = make_response("这是设置cookie的操作")
    response.set_cookie('username',mao,max_age=30)
    response.set_cookie('pwd',123456,max_age=30)
    return response

读取cookie和session
@app.route('/read)
def read():
    return "您当前的昵称是%s" %session.get('username')
    return "%s"request.cookies.get('username')

session写在后台,可以在一个函数中读写。
cookie无法在同一个接口中写入后马上获取。

flask框架核心

  1. 拦截器:对接口请求进行预先处理,然后处理交由控制器。

1)全局拦截器,应用于flask实例(app)中,对所有经过当前系统的请求进行拦截检查。
a)全局拦截器,要设置好白名单,
2)模块拦截器,只针对某一种模块进行拦截,应用于Blueprint模块中

#全局拦截器
白名单:
1.所有的静态资源(JS,image,css等)必须设置为白名单
2. 登录或者注册等不需要拦截的页面,或会影响权限操作的页面
根据业务需求,也可以设置黑名单
@app.before_request
def defore_request():
    user_id = session.get("user_id")
    if user_id:
        try:
            user = UserModel.query.get(user_id)
            # 给g绑定一个叫做user的变量,他的值是user这个变量
            # setattr(g,"user",user)
            g.user = user
        except:
            g.user = None

pass_list = ['/','/reg','/login']
suffix = url.endswith('.png') or url.endswith('.jpg') or url.endswith('.css') or url.endswith('.js')
if url in pass_list or suffix:
    pass
else:
    #开始拦截

#模块拦截器
写在蓝图中,只对蓝图中的控制器起拦截作用
@bp.before_request
def defore_request():
    url = request.path #读取到当前接口的地址
    if url == '/session':
        PASS
    elif session.get('islogin') != 'true':
        return "未登录"
    else:
        PASS

jinja2模板引擎

  1. 语法
    (1){%…%}用于循环或者判断语句,赋值等等
判断:
{%if ....%}
{%else%}
{%endif%}
循环:
{%for i in range(10)%}
{%endfor%}
赋值:
{% set loop=100/10%} {# loop的值为10.0,是float类型#}
{% set intloop = loop | int%} {# 使用过滤器将loop强制转换为int#}

(2){{…}}用于表达式的值的引用
(3){#…#}用于模板引擎的注释,如果注释中存在模板引擎的语法,那么使用 将不被模板引擎认为是注释,注释中的语法将被执行,此时用{#…#}进行注释。

  1. 定义一个函数,供jinja2调用
    1)第一种文案,使用上下文处理器来注册自定义函数到jinja2模板引擎中,并且返回一个字典类型的数据
@jinja2.context_processor
def fun():
    type={'1':'learning_notes','2':'postgraduate'}
    return dict(mytype=type)
前端调用的是mytype,于函数名无关

2)第二种方法,按照标准的函数调用的方式进行,需要放到app中

def fun1():
    type={'1':'learning_notes','2':'postgraduate'}
    return type
app.jinja2.env.globals.update(mytype=fun1)
app.jinja_env.filters.update(mytruncate=mytruncate)
  1. 如果要为自定义的函数传参,则需要使用二层闭包进行包裹
@jinja2.context_processor
def fun():
    def myfunc(args):
        type={'1':'learning_notes','2':'postgraduate'}
    return dict(mytype=myfunc)
  1. 模板的继承
1)在母版中,后续需要插入内容的位置插入
{% block content%}
{% endblock%}
2)在需要导入母版的页面写入
{% extends 'base.html'%} {# 当前页面继承至base.html母版#}
{% block content %}
.....
{% endblock %}
3)按需引入side.html,在需要的页面引入
{% include 'side.html' %}
  1. 错误页面
@app.errorhandler(500)
def func(e):
    return render_template('error-500.html')

@app.errorhandler(404)
    def func(e):
    return render_template('error-.html')

数据库

1.pymysql+python魔术方法(dict,
setattr,getattribute)
2. ORM:
a) Object-Relational Mapping:对象-关系映射。把数据转换成python对象。进而实现数据库的操作对象化。
b) 数据库中的表->python的类
c)表里面的列->类的属性
d)表里面的行->类的实例,字典对象表述
e)字典对象的Key对应列,Value对应值
f)对增删改查进行封装
flask框架本身是最小化web服务内核,表与表之间的关系,不一定要定义在数据库中,心中有关系就行。(数据库为了维护主外键关系,会增加额外消耗)
删除数据时,尽量使用软删除(设置标识),而不是直接硬删除(Delete from-会索引重建)。

SQLAlchemy

  • 查询
.first() -> 直接返回一行数据对象
.all() -> 直接返回包含多条数据对象的列表
.filter_by(x=y,a=b) -> 只适用于等值查询,其参数为字典参数的传值方式
.filter() -> 适用于复杂查询条件的对比,其参数为条件运算
查询过程中,可以使用db.session的方式进行查询(支持多表),也可以使用model.   query的方式进行查询(不支持多表),所以优先使用db.session。

基础查询汇总,直接打印一个类的时候,具体打印什么内容,由类的__repr__魔术方法决定,可以重写

```python
# select * from users
result = dbsession.query(Users).all()
# select userid, username from users
result = dbsession.query(Users.userid,Users.username).all()
# select * from users where userid=1 and qq='12345678'
result = dbsession.query(Users).filter_by(userid=1,qq='12345678').all()
# select * from users where userid>7 or nickname='丹尼'
result = dbsession.query(Users).filter(or_(userid>7 , users.nickname=='丹尼')).all()
# select * from users limit 3
result = dbsession.query(Users).limit(3).all()
# select * from users limit 3,5
result = dbsession.query(Users).limit(5).offset(3).all()
# select count(*) from users where ....
count= dbsession.query(Users).filter(User.userid > 3).count()
# select distinct (qq) from users
result= dbsession.query(Users.qq).distinct(Users.qq).all()
# select * from users order by userid desc
result= dbsession.query(Users).order_by(Users.userid.desc()).all()
# select * from users where username like '%qiang%'
count= dbsession.query(Users).filter(User.username.like('%qiang%')).all()
# select * from users group by role
result= dbsession.query(Users).group_by(User.role).all()
result= dbsession.query(Users).group_by(User.role).having(Users.userid>2).all()
# 聚合函数:min,max,avg,sum
# select sum(credit) from users
result = dbsession.query(func.sum(Users.credit)).first()
# filter : == >= > <= < !  in not 
  • SQLAlchemy连接查询和其他
  1. 内连接
# select * from article inner join users on article.userid=user.userid where article.articleid=1
# 多表连接查询时,返回的结果集不再是单纯的[Model,Model]数据结构,而是每张表的结果由独立的对象来维护
result = dbsession.query(Article,Users).join(Users,Article.userid == Users.userid).filter(Article.article==1).all()
result= dbsession.query(Article,articleid,Users.nickname).join(Users,Article.userid == Users.userid).filter(Article.article==1).all()
  1. 外连接
# 查询每一个用户发表过的文章的阅读总量,outerjoin默认为左外连接
# select users.userid,user.nickname,sum(article.readcount) as total from users left join article on users.userid= article.article.userid group by (users.userid)
result = dbsession.query(Users.userid,Users.nickname,func.sum(Article.readcount)).outerjoin(Article,Users.userid==Artilce.userid).group_by(Users.userid).all()
  1. 复杂查询:and和or混用,username like ‘qiang’ or (userid>3 and nickname=‘reader3’)
result = dbsession.query(Users).filter(or_(users.username.like('%qiang%'),and_(Users.userid>3,Users.nickname=='reader3'))).all()
result = dbsession.query(Users).filter(and_(Users.username.like('%qiang%'),or_(Users.userid>3,Users.nickname=='reader3'))).all()
result = dbsession.query(Users).filter(Users.username.like('%qiang%'),or_(Users.userid>3,Users.nickname=='reader3')).all()
  1. 三表连接
result = dbsession.query(Comment,users).join(Users,Comment.userid==Users.userid.join(Article,Article.articleid==Comment.articleid).all()
  1. 利用SQLALchemy执行原生sql
result= dbsession.execute("select * from users where userid>5").fetchall()
  • SQLAlchemy与JSON
    JSON:JavaScript Object notation 是javascript的内置数据格式,由javascript的数组、对象构成
    [{},{},{}]
    {[],[],[]}
    {{},{},{}}
    JavaScript的数组 --> python列表是完全一致的定义方式
    javascript的对象 --> python的字典是完全一致的定义{key:value,key:value}

实现首页内容填充

。。。。。。

  • 重写truncate过滤器
    1.修改源码,修改jinja2的truncate的源代码
  1. 自定义一个函数,并在jinjia模板中注册
  • 利用JavaScript处理json的方式进行原生代码的前端渲染
    a) 通过后台:原生python输出html,使用模板引擎。浏览器直接绘制html。
    b)通过前端:使用JavaScript动态输出填充DOM元素(json)。对搜索引擎不友好。前后端分离(web app主流开发模式) -> 核心思想:字符串拼接。
    c) 前后端分离可以有效减少服务器渲染html的资源消耗,把渲染的过程交给前端浏览器处理。
  • 利用vue进行前端渲染
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>

<ul id="recommended_article">
    <li v-for="(article,index) in content">
        <a v-bind:href="'/article/'+article[0]">${index}}.&nbsp;&nbsp;${article[1].substr(0,4)}}</a>
    </li>
</ul>

<!-- 
1. 填充时绑定JSON数据,进行类似于jinja2的填充方式 
2. 循环:v-for 来指定循环,写在需要循环的标签语句内
-->

var v = new Vue({
    el: '#recommended_article', //绑定的元素不能与v-for同级,最好上级
    data: {"key" : "value"},
    delimiters: ['${' , '}}']  //自定义分隔符,左边和右边
});

登录和注册

  • 图片验证码和邮箱验证码
  1. 验证码:图片验证码,邮箱验证码,短信验证码
  2. 实现原理:前端输入-》后台接收地址进而生成随机验证码(同时将该验证码保存起来:session,文件或数据库,缓存服务器)-》返回给用户-》用户填写并提交到后台-》后台进行对比校验
  3. 验证码的作用:
    a)防止自动化代码(爬虫、恶意脚本)来直接发送请求
    b)确认用户信息的真是性:邮箱地址,手机号码
  4. 图片验证码的功能实现:
    a)绘制基础的图片,使用pillow将随机验证码文本绘制成一张图片。字体,变形,干扰线
    b)将验证码图片响应给前端,供前端用户识别并提交给服务器
    c)校验。成功,则执行后续代码,否则,用户重新提交
切花验证码图片,欺骗浏览器url变化,重新请求一个地址
onclick="this.src='/user/vcode?'+Math.random()"
  1. 邮件验证码:
    a) 需要支持邮件发送或者接收的模块
    b)需要一台
  • 用户注册
    a) 向users表插入一条记录
    b) 新用户,赠送50积分
    c) 向credit表插入一条积分详情
    d) 用户注册成功直接保持登录状态
添加一个回车事件响应,当返回的事件为null时执行下面的代码,当返回事件等于为enter时执行下面代码。
function doReg(e) {
    //回车事件
    if(e != null && e.keyCode !=13){
        return false;
    }
    
    var regname = $.trim($("#regname").val());
    var regpass = $.trim($("#regpass").val());
    var regcode = $.trim($("#regcode").val());


<button type="button" class="btn btn-primary" onclick="doReg(null)">注册</button>

<input type="text" id="regcode" class="form-control col-4"
                                           placeholder="请输入邮箱验证码,不区分大小写" onkeyup="doReg(event)">
  • 用户登录

  • 自动登录
    a)利用cookie的持久化存储机制来保存用户登录信息
    i.session ID
    ii. 利用利用加密机制,存储一个自定义规则的GUID
    iii. 直接保存username 和password(MD5),直接将cookie发送给服务器

    1. 在登录成功后,将cookie写入浏览器
    2. 在接口中,从cookie中获取用户名和密码,并完成登录验证

b)利用全局拦截器实现自动登录的处理

文章

页面静态化处理技术

1.优化网络
2.优化硬盘
3.优化CPU:CPU是系统中容易出现

  • 静态化:HTML(JS+CSS) -> 动态生成内容(处理)->模板引擎 -> 消耗服务器资源。

  • 如何将动态内容静态化

    1. 预处理:直接把数据库查询和模板渲染的过程先实现一遍,但是不响应,而是直接将渲染完成后的页面写入HTML文件中
    2. 当访问首页时,直接读取首页对应的HTML页面文件。
    3. 如果访问第二页时,则同样地读取第2页对应的HTML文件。
    4. 页面没有更新?即使增加了新文章,也无法即使反馈给前端
    a)定时触发更新
    b)新增时触发更新:在新增接口中,直接删除已有静态页面。
    c)用户访问时触发更新:用户访问时,先判断是否存在静态页面,存在直接响应,否则先查询、渲染后再响应,并同时生成静态页面。
    d)手动删除策略
    

    5.伪静态:通过路由规则的定义,来模拟一个.html后续的URL地址,让用户或搜索引擎误以为这是一个HTML静态页面。对性能提升没有一点作用

Redis

Redis官网:https://redis.io/
windows下载地址:https://github.com/MicrosoftArchive/redis/releases
redis命令参考:http://doc.redisfans.com/

  1. 什么是缓存:高速设备代替低速设备承载更多处理能力和IO操作。
  2. Redis是一个内存型数据库,用于缓存硬盘数据,进而提示性能
  3. 为什么需要缓存:让内存代替硬盘去做更多的事,内存比硬盘快至少100倍,通过缓存可以更好支撑高并发。
  4. Redis等内存型数据库通常事“非关系型数据库”,以key-value存储
  5. redis默认有16个数据库,[0-15],默认使用0

数据类型

数据类型KeyValue注意事项
字符串(String)username
password
maohui
123456
Redis没有数字类型,归为字符串类型中
哈希(Hash)articleKey:article Value:后台框架调优Hash类型的值本身又是一个键值对的字典类型
列表(List)headlineFlask的路由规则,RESTful接口规范列表中的值可以重复,也可以存JSON数据,也可以存JSON数据
集合(Sets)phone213,567集合的用法与列表类似,只是存的值不允许重复
有序集合(Sorted Sets)phone123,456有序集合也称ZSet,当值写入后将会进行排序后保存

下载安装

  • windows
1.进入github地址进行安装
2. 进入redis目录,启动服务端
redis-server.exe redis.windows.conf
3. 再打开一个命令窗口,启动客户端
redis-cli
4. 可视化工具:Redis Desktop Manager

ubuntu指定文件启动,将文件中的daemonize yes,
sudo redis-server /etc/redis/redis.conf

Redis持久化

将数据从redis保存到磁盘中,因为不保存,重启redis的话,数据会丢失。

  1. RDB持久化方式能够在指定的时间间隔内对数据进行快照存储,这也是redis默认的持久化策略。
  2. AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据。默认关闭,开启:appendonly 改为yes。

python操作Redis

原生使用tcp/ip传输,直接用socker就可以发

关于缓存更新的策略思考

  • 从数据库的表中全部把数据一次性保存到缓存中,然后从缓存中去取
  • 按需存取:要去读取一条数据,优先从Redis取,如果Redis里面没有,则再向Mysql中取(如果数据是第一次取,则必然会从数据库中去取),取得同时,同步将该条数据缓存到Redis中。(第二次取值时,则会从Redis中取到,并且Redis也进行了更新)
  • Redis的Key如何设计?
    1. 使用路由地址+参数 是否可以作为Key?比如 redis_page_15或login-username-maohui@qq.com
    2. 使用 函数和方法名 +参数作为Key? paginate_redis_15。
    3. 使用任意表格当中的列作为Key
    4. 使用表格当中的多个列合并为Key
  • 在同一个系统中,存在Redis数据源和MySQL数据源时,对于数据的操作,还有一些可能出现的异常情况
    1. 雪崩:集群,哨兵、消息队列
    2. 如果Redis的内存已经存满了:数据的情况下,如何处理?LRU 最近最少使用算法。
  • 后台架构(架构师)
    1. 高可用。7*24小时不间断服务。集群
    2. 高并发。
    3. 系统瓶颈的相对比例。
    4. 高性能。高并发,正常并发,长时间运行。。。。。。
    5. 安全性(Security)。
    6. 针对方案进行专题测试并进行优化

部署Blog

参考博客:
部署:https://blog.csdn.net/weixin_42118531/article/details/106592752
python虚拟环境:https://blog.csdn.net/weixin_39860919/article/details/110703314

  1. linux操作系统
  2. python运行环境
  3. git环境
  4. 安装运行uwsgi,创建uwsgi.ini以及uwsgi.py
pip3 install uwsgi
安装就可以了。(uwsgi必须安装在系统级别的Python环境中,不要安装到虚拟环境中)。然后创建一个叫做uwsgi.ini的配置文件,uwsgi.py文件替代app.py
启动执行uwsgi.ini文件,同时项目也是启动状态:
uwsgi --ini uwsgi.ini
  1. 安装ngnix
    优点:
    • uwsgi对静态文件资源处理并不好,包括响应速度,缓存等。
    • nginx作为专业的web服务器,暴露在公网上会比uwsgi更加安全一点。
    • 运维起来更加方便。比如要将某些IP写入黑名单,nginx可以非常方便的写进去。而uwsgi可能还要写一大段代码才能实现。
1. 安装:
sudo apt-get install nginx
# nginx简单操作命令
启动:sudo systemctl start nginx
关闭:sudo systemctl stop nginx
重启:sudo systemctl restart nginx
2. 添加配置文件
sudo vim /etc/nginx/conf.d/blog.conf
sudo nginx -t
如果不报错,说明成功。 每次修改完了配置文件,都要记得运行
systemctl start nginx
# /etc/nginx/nginx.conf
sudo vim /etc/nginx/nginx.conf 
# xxx是本机的root权限的用户名
user xxx;
# 重启nginx
systemctl restart nginx
# 运行项目
uwsgi --ini uwsgi.ini

部署遇到的问题:

  1. 成功解决 OSError cannot open resource
    原因:其中用到的字体 simsun 在 Ubuntu 系统中可能并没有,怎么办呢?其实也很容易,我看到好多博客都是说 Windows 系统怎么解决的,在 Windows 系统下,可以进入 C:\Windows\Fonts 目录下,把里面的可用字体的路径复制到程序中的调用部分就可以了。
    受此启发,只要也在 Linux 系统中,找到系统自带的字体,然后把路径改了就行。
    在 Linux 下,查看系统字体路径的命令为
fc-list
使用 /usr/share/fonts/truetype/dejavu中的字体,或者把要用的字体下载到此文件夹下就可以了
例如:DejaVuSans.ttf
  1. 在app.py的文件中,在if name ="main"下导入注册的蓝图时,无法访问蓝图路由,error“404”
if __name__ == '__main__':

    # 将注册蓝图放在这里,解决循环导入问题(或者将蓝图中导入数据库模块的操作放在函数中)
    from apps import *  # 导入init中的蓝图
    app.register_blueprint(index_bp)  # 注册蓝图
    app.register_blueprint(user_bp)  # 注册蓝图
    app.register_blueprint(article_bp)
    app.register_blueprint(post_bp)
    app.run(debug=True, host='0.0.0.0', port=3355)

You are calling your app.register_blueprint in a function that will never be seen by the wsgi server.

I’m guessing you have followed some kind of guide that makes these nice functionsfor you to configure/initialise etc the app. But it is purely made for the development server it would seem.

You have to call Blueprint and init_app outside the functions, or create a new wsgi.py file that imports app and then runs the Blueprint and api.init_app commands.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值