Python框架Flask开发菜鸟入门

3600字带你入门Python框架Flask

Flask 框架

1.Flask介绍

flask 是一门使用 python 编写的后端框架。

另外一门非常优秀的 Django 框架:

目前是建议是初学者使用 flask 进行开发。

因为 Django 有着一系列复杂的我们并不需要使用的功能。

python环境

如果没有 python 的环境的话,请安装最新的 python 环境即可。

flask安装

 pip install Flask

记得把天杀的梯子关了。

开发工具pychram

请到官网下载。(专业版最好

实在要用 vscode 也一样。

2.第一个项目

项目目录

 # 从 Flask 这个包中导入 flask 这个类
 from flask import Flask
 
 # 使用Flask类创建一个app对象
 # __name__ 代表当前的这个模块
 # 1.以后出现bug,它可以帮助我们快速定位
 # 2.对于寻找模板文件,有一个相对路径
 app = Flask(__name__)
 
 # 创建一个路由和视图函数的映射
 # 创建的是根路由
 # 访问根路由,就会执行hello_world这个函数
 @app.route('/')
 def hello_world():  # put application's code here
     return 'Hello World!'
 
 # 运行代码
 if __name__ == '__main__':
     app.run()

执行:

pychram 直接点击右上角直接运行;

vscode 可以在终端中输入 flask run 也可以运行。

3.项目配置

debug模式

默认是没有开启的。

如果没有开启 debug 模式的话,你修改完代码后必须将项目停止,然后重启才能够有效果。(我们希望的效果当然是直接保存然后就有效果)

所有一般我们打开 debug 模式。

如何开启:

不仅如此,开启了 debug 模式之后,如果报错了,我们在浏览器上就可以看到报错信息。

此外:也可以在代码中直接修改

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

修改host

默认情况下是 localhost:

但是外部是不能访问的。

如果想让在同一个网络下的其他设备可以访问的话,需要修改为0.0.0.0

然后我们就可以使用ip地址进行访问。

如何修改host:

或者也可以使用 --host=你的ipaddress也行。

效果:

修改端口号

就是修改项目运行的端口号。

还是在刚刚修改host的地址。

4.url与视图

url的组成部分:

协议 + 域名 + 端口号(默认是80 \ 443) + 路由

我们使用 @app.route()即可定义路由:

 @app.route('/')
 def hello_world():  # put application's code here
     return '你好china'
 
 @app.route('/my')
 def my():  # put application's code here
     return '这里是李嘉俊'

也可以定义多层。

url携带参数

 @app.route('/my/blog/<blog_id>')
 def blog_detail(blog_id):  # put application's code here
     return '您访问的博客是{}'.format(blog_id)

参数携带类型

如果携带类型的话,能够强制转换的话会被强制转换。

可以定义的类型:

默认参数

 /book/list
 /book/list?page=2

使用 request

 from flask import Flask,request
 @app.route('/book/list')
 def book_detail():  # put application's code here
     page = request.args.get('page', default=1, type=int)
     return '你获取的是{}'.format(page)

请求类型

post 和 get ......

5.模板渲染

模板引擎:Jinja2

虽然 jinja2 是一个单独的库,但是由于 flask 依赖了jinja2,所以不必单独安装。

引入:

 from flask import render_template

使用:

 @app.route('/template')
 def template():  # put application's code here
     // 渲染
     return render_template('demo.html')

效果:

动态渲染

还是使用 jinja2 的 render_template

 @app.route('/template/blog/<blog_id>')
 def template(blog_id):  # put application's code here
     return render_template('demo.html', blog_id=blog_id)
 <!DOCTYPE html>
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
     <title>Title</title>
   </head>
   <body>
     <a href="www.baidu.com">百度</a>
     <div class="header">这里是博客{{ blog_id }}</div>
   </body>
 </html>

效果:

模板访问对象属性

一样的:

 @app.route('/template/blog/<blog_id>')
 def template(blog_id):  # put application's code here
     uesr = User('lijiajun', 'wy15195382735@163.com')
     person = {
         'username': 'zhangsan',
         'email': 'zhangsan的email'
     }
     return render_template('demo.html', blog_id=blog_id, user=uesr, person=person)
 <!DOCTYPE html>
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
     <title>Title</title>
   </head>
   <body>
     <a href="www.baidu.com">百度</a>
     <div class="header">这里是博客{{ blog_id }}</div>
     <div>{{ user }}</div>
     <div>{{ user.username }}</div>
     <div>{{ user.email }}</div>
     <div>{{ person.username }}</div>
     <div>{{ user.email }}</div>
   </body>
 </html>

结果:

6.jinja2过滤器

使用过滤器

使用管道符号 | 即可。

就是处理从render_template中传入的一些数据,可以在 template 中使用 jinja2 的过滤器。

比如求传入的长度:

   <div>{{ user.email | length }}</div>

有几十个内置的过滤器,查看 jinja2 的文档即可。

自定义过滤器

自定义相关函数,然后增加即可。

 # 自定义过滤器
 def filter(value):
     return value.upper()
 
 
 # 增加过滤器
 app.add_template_filter(filter, 'filter')
 <div>{{ user.email | filter }}</div>

效果:

7.jinja2控制语句

if语句

 <div>
     {% if age > 18 %}可以进入 {% endif %} {% if age < 18 %} 禁止进入{% endif %}
 </div>

效果:

for循环

注意没有 break 这样的语句。

 <div>
     {% for foo in age %}
 ​
     {% endfor %}
 ​
 </div>

8.jinja2模板继承

封装组件

就是组件,在这里称为需要复用的模板。

举例:我们新建一个组件:

在别的页面中使用:

 {% extends 'component.html' %}

组件传参

demo.html

 <!DOCTYPE html>
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
     <title>test</title>
   </head>
   <body>
     <div>
       {% extends 'component.html' %} {% block content %} 我是传过来的内容 {%
       endblock %} {% block title %} 我是传过来的标题 {% endblock %}
     </div>
   </body>
 </html>

component.html

在其中留空即可。

 <!DOCTYPE html>
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
     <title>这是一个组件</title>
   </head>
   <body>
     这是一个组件 {% block title %}{% endblock %} {% block content %}{% endblock
     %}
   </body>
 </html>

效果:

9.jinja2中加载静态文件

加载图片

 <body>
     <div>
         <img src='{{ url_for("static",filename="image.png") }}' alt="" />
     </div>
 </body>

结果:

加载css文件

 <head>
     <meta charset="UTF-8" />
     <title>test</title>
     <link rel="stylesheet" href='{{ url_for("static",filename="demo.css") }}' />
 </head>

效果:

加载js文件

一样的:

 <script src='{{ url_for("static",filename="demo.js")}}'></script>

总结

都是使用 {{ url_for('static',filename="demo")}} 就可以了。

10.操作数据库(Mysql)

安装相关包

  • MySQL-python:老旧的包,只支持 py2
  • mysqlclient:对上面这个包的改善,支持了 py3,是目前的驱动包中效率(纯c语言编写)最高的,但安装的时候环境容易出问题
  • pymysql:纯 py 编写,效率比较低,但是正因为如此,它可以和 python 无缝衔接
  • mysql-connector-python:纯 py 写的,比上面这个还慢

为了减少出错:可以使用 pymysql

 pip install pymysql

我们不会直接使用这个包去操作数据库,因为需要写原生的SQL语句,我们最好使用 orm。

所以我们还需要下一个:

 pip install flask-sqlalchemy

sqlalchemy 给我们提供了 orm 的技术,可以让我们像操作普通对象一样去操作数据库。

这个需要额外安装,因为 flask 没有这个依赖。

连接数据库

  • 在 app.config 中设置好连接数据库的相关信息
  • 然后使用 SQLAlchemy(app)创建一个 db 对象
  • SQLAlchemy 会自动读取 app.config 中的连接信息
 # 从 Flask 这个包中导入 flask 这个类
 from flask import Flask, request, render_template
 from flask_sqlalchemy import SQLAlchemy
 from sqlalchemy import text
 
 app = Flask(__name__)
 # 配置文件
 HOSTNAME = '127.0.0.1'
 PORT = 3306
 USERNAME = 'root'
 PASSWORD = 'admin123'
 DATABASE = 'my_db_01'
 print('mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8mb4'.format(USERNAME, PASSWORD,
                                                               HOSTNAME, PORT,
                                                               DATABASE))
 app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8mb4'.format(USERNAME, PASSWORD,
                                                                                                 HOSTNAME, PORT,
                                                                                                 DATABASE)
 db = SQLAlchemy(app)
 
 with app.app_context():
     with db.engine.connect() as conn:
         rs = conn.execute(text("select 1"))
         print(rs.fetchone())

结果:

orm模型与表的映射

orm(object relationship mapping) : 对象关系映射,是一种可以利用 python 面向对象的方式来操作关系型数据库的技术。
优点:

  • 开发效率高,不需要写 SQL 语句
  • 安全性强:对常见的 SQL 问题进行了处理,比如 SQL 注入等等
  • 灵活性强:flask-sqlalchemy的orm支持一系列关系型数据库,只需要在连接的时候正确配置即可

写法:

 # User orm
 class User(db.Model):
     # 映射表名
     __tablename__ = 'user'
     # 配置数据库元素
     # id,username,password 的各自的属性(主键,类型,是否可以为空,自增等等)
     id = db.Column(db.Integer, primary_key=True, autoincrement=True)
     username = db.Column(db.String(100), nullable=False)
     password = db.Column(db.String(100), nullable=False)
 
 # 下面的语句实际上就是映射为 insert 语句
 user = User(username='法外狂徒张三',password='111111')
 
 # 将你创建的表推到数据库
 with app.app_context():
     db.create_all()

如果数据库中已经有相关的表的话,也就是说我们不需要在代码中新建表,我们直接读取数据库中的表:

 from flask_sqlalchemy import SQLAlchemy
 
 db = SQLAlchemy()
 
 my_table = db.Table('my_table',
                     db.Column('id', db.Integer, primary_key=True),
                     db.Column('name', db.String(50)),
                     db.Column('age', db.Integer))

orm与crud操作

create

 @app.route('/user/add')
 def addUser():
     user = User(username='法外狂徒张三', password='111111')
     db.session.add(user)
     db.session.commit()
     return '新建用户成功'

read

 @app.route('/user/read')
 def readUser():
     # get 查找:根据主键查找
     user = User.query.get(1)
     return '查找用户成功{}{}'.format(user.id, user.username)
 @app.route('/user/read')
 def readUser():
     # 1.get 查找:根据主键查找
     # user = User.query.get(1)
     # 2.使用 filter_by 查找
     users = User.query.filter_by(username='法外狂徒张三')
     print('this is users', users[0].username)
     return '查找用户成功'

update

 @app.route('/user/update')
 def updateUser():
     user = User.query.filter_by(username='法外狂徒张三').first()
     user.username = '法外狂徒李嘉俊'
     db.session.commit()
     return '修改用户成功'

delete

 @app.route('/user/delete')
 def deleteUser():
     # 查找
     user = User.query.filter_by(username='法外狂徒李嘉俊').first()
     # 从 db.session 中删除
     db.session.delete(user)
     # 提交删除
     db.session.commit()
     return '删除用户成功'

orm外键与表关系

了解一下就行。

关于外键:

  • 在实际生产中基本不用
    • 因为本质上是一种耦合的体现
    • 数据表之间的查询效率不高
    • 如果有分布式的情况存在就更无法使用外键
  • 代替
    • 使用另外一张表代替,就像多对多一样
    • 使用外键但不建立外键的约束

orm映射到数据库

我们之前使用这样的方式来将模型映射到数据库:

 # 将你创建的表推到数据库
 with app.app_context():
     db.create_all()

但是如果模型中的字段改变了,就会出现问题。

比如:

原来我们的模型:

 # user 模型
 class User(db.Model):
     # 映射表名 -> 就是数据库中表名
     __tablename = 'user'
     # 配置数据库元素
     # id,username,password 的各自的属性(主键,类型,是否可以为空,自增等等)
     id = db.Column(db.Integer, primary_key=True, autoincrement=True)
     username = db.Column(db.String(100), nullable=False)
     password = db.Column(db.String(100), nullable=False)

我们这时候添加一个 email

 # user 模型
 class User(db.Model):
     # 映射表名 -> 就是数据库中表名
     __tablename = 'user'
     # 配置数据库元素
     # id,username,password 的各自的属性(主键,类型,是否可以为空,自增等等)
     id = db.Column(db.Integer, primary_key=True, autoincrement=True)
     username = db.Column(db.String(100), nullable=False)
     password = db.Column(db.String(100), nullable=False)
     email = db.Column(db.String(50), nullable=False)

但是数据库中并不会增加 email 字段。

甚至你如果想修改原来的字段的一些信息:

都是会无法修改的。

所以实际开发中我们并不会使用 db.create_all()

这时候我们需要一个第三方的包,叫做 flask-migrate

 pip install flask-migrate

引入:

 from flask_migrate import Migrate

初始化:

 migrate = Migrate(app,db)

映射:

  • flask db init 只需要执行一次
  • flask db migrate 识别 orm 模型的改变,生成迁移脚本
    注意原来这个 version 中的没有文件

当我们修改过模型之后,可以执行代码,然后:

  • flask db upgrade 运行迁移脚本,同步到数据库中

可以看出,数据库中的字段已经发生了改变,同时生成了一张用于记录 version 的表:
(存储的当前最新的 version)

千万注意,使用这三步走,会重置整个数据库,比如你原来数据库中有除了本项目代码以外的数据模型,会被删除。千万注意!

但是我感觉这种方法也不是很方便,不知道会不会有更简单的方法。

11.蓝图blueprint

学习自认识flask 蓝图(blueprint)技术 - 知乎 (zhihu.com)

蓝图结构

我们在写项目的时候,肯定是不能够将所有的接口都写在同一个页面中的。

如果接口很少的话,我们甚至只需要使用一个页面,就是 app.py 就可以解决后台的开发,但是实际上的开发往往会比较复杂,这时候我们就需要将代码模块化。

这时候我们就需要使用蓝图。

蓝图技术可以帮助我们实现 flask 应用的模块划分。

 blue-print/
 ├── admin
 │   ├── __init__.py
 │   └── views.py
 ├── app.py
 └── user
     ├── __init__.py
     └── views.py

接下来请看各个部分的代码:

app.py

 from falsk import Flask
 app = Flask(__name__)
 
 // 引入
 from admin import admin_blue
 from user import user_blue
 
 @app.route('/')
 def hello():
     return 'hello'
 
 app.register_blurprint(admin_blue)
 app.register_blurprint(user_blue)
 
 if(__name__ == '__main__'):
     app.run(port=5001)

user init 模块

 from flask import Blueprint
 
 # 用户部分接口的统一头
 user_blue = Blueprint('user',__name__,url.prefix='/user')
 from . import views

user views 模块

 from user import user_blue
 
 # 用户部分的接口
 @user_blue.route('/register')
 def register():
     return 'register'
 
 @user_blue.route('/login')
 def login():
     return 'login'
 
 @user_blue.route('/modify_password')
 def modify_password():
     return 'modify_password'

admin init 模块

 from flask import Blueprint
 
 # 用户部分接口的统一头
 admin_blue = Blueprint('admin',__name__,url.prefix='/admin')
 from . import views

admin views 模块

 from admin import admin_blue
 
 # 用户部分的接口
 @admin_blue.route('/alluser')
 def register():
     return 'alluser'
 
 @admin_blue.route('/deluser')
 def login():
     return 'deluser'

如上,这样的划分的话,就会好很多。

关于代码组织形式

蓝图在组织代码的时候,一共有两种组织形式

  • 功能性架构
  • 分区式架构

我们上面所展示的就是功能性架构,很明显,我们就是按照功能模块来组织的蓝图,他们共用着相同的静态资源,一起放在 static 中

一个功能性架构的目录示意图:

 __init__.py
 static/
 templates/
     home/
     control_panel/
     admin/
 views/
     __init__.py
     home.py
     control_panel.py
     admin.py
 models.py

关于分区式架构:

适用于子模块有特殊需要的情况下,在创建蓝图对象时,可以指定 static 和 template ,结构大致如下:

 app/
     __init__.py
     admin/
         __init__.py
         view.py
         static/
         template/
     home/
         __init__.py
         view.py
         static/
         template/
     control_panel/
         __init__.py
         view.py
         static/
         template/
     models.py
THE END