py01-python之flask笔记

发布时间 2023-11-30 16:37:40作者: 王枫子

一、前奏

from flask import Flask  # 从flask包导入Flask类

app = Flask(__name__)  # 使用Flask类创建一个app对象
"""
1、__name__:代表当前app.py这个模块
2、作用:出现bug快速定位,对于寻找模板文件有一个相对路径
"""


@app.route('/')  # 创建一个路由和视图函数的映射,/是根路由
def hello_world():
    return 'Hello World!'


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

1、debug模式:app.run(debug=True)
(1)开启debug模式后,只要修改代码后保存,就会自动重新加载,不需要手动重启项日
(2)如果开发的时候,出现bug,如果开启了debug模式,在浏览器上就可以看到出错信息
2、修改host:让其他电脑能访问到我电脑上的fLask项目。修改port端口号:如果5000端口被其他程序占用了,那么可以通过修改port来监听新端口号
(1)app.run(debug=True, host="0.0.0.0", port="8000")
3、urL与视图:path与视图

@app.route('/')
def hello_world():
    return 'Hello World!'
@app.route("/profile")
def profile():
    return '我是个人中心!'
@app.route("/blog/<int:blog_id>")
def blog_list(blog_id):
    # 带参数的urL;将参数固定到了path中
    return “您访间的博客是:%s” % blog_id
@app.route('/book/list')
def book_list():
    # arguments:参数。request.args:类宇典类型
    page = request.args.get("page",default=1,type=int) # 参数page,默认1。/book/list?page=2:获取第二页的数据
    return f"您获取的是第{page}的图书列表!"

备注:除了int 类型以外,URL中的参数还可以指定以下类型
(1)string:字符串类型。可以接受除/以外的字符
(2)int:整形。可以接受能通过int()方法转换的字符
(3)float:浮点类型。可以接受能通过float()方法转换的字符
(4)path:路径。类似string,但是中间可以添加/
(5)uuid:UUID类型。UUID是由一组32位数的16进制所构成
(6)any:备选值中的任何一个

二、模板渲染(基于jinja2)

1、实际网站开发中,为了让网页更加美观,是需要渲染一个有富文本标签的页面,通常包含大量的HTML代码,如果把这些HTML代码用字符串的形式写在视图函数中,后期的代码维护将变得噩梦一般。
因此,在Flask中,渲染HTML通常会交给模板引擎来做,而Flask中默认配套的模板引擎是Jinja2,Jinja2的作者也是Flask的作者,Jinja2可以独立于Flask使用,比如被Django使用。Jinja2是一个高效、可扩展的模板引擎。

@app.route("/blog/<blog_id>")
def blog_detail(bloq_id):
    return render_template("blog_detai.html",blog_id=blog_id,username="派森")
# render_template:接收HTML文件和传给HTML文件的变量

三、模板访问对象属性(基于jinja2)

from flask import Flask,render_template

app=Flask(__name__)

class User:
    def __init__(self,username,email):
        self.username = username
        self.email= email

@app.route('/')
def hello_world():
    user = User(username="派森",email="xx@qq.com")
    person = {
        "username":"张三",
        "email": "zhangsan@qq.com"
    }
    return render_template("index.html",user=user,person=person)
    
## html中:
<div>{{ user.username }} / {{ user.email }}</div>
<div>{{ person['username'] }} / {{ person.username }}</div>

四、过滤器的使用(基于jinja2)

1、在Python 中,如果需要对某个量进行处理,我们可以通过函数来实现。在模板中,我们则是通过过滤器来实现的。过滤器本质上也是函数,但是在模板中使用的方式是通过管道符号(|)来调用的
例如有个字符串类型变量namme,想要获取他的长度,则可以通过{{name | length}}来获取,length是Jinja2内置好的过滤器
2、自定义过滤器:过滤器本质上是Python的函数,他会把被过滤的值当做第一个参数传给这个函数。函数经过一些逻辑处理后再返回新的值
在过滤器函数写好后,可以通过@app.template_filte装饰器或者是app.add_template_filter函数来把函数注册成Jinja2能用的过滤器

def datetime_format(value,format="gY-%d-mH:M"):
    return value.strftime (format)
app.add_template_filter(datetime_format,"dformat")

上面我们定义了一个datetime_formmt的函数,第一个参数是需要被处理的值,第二个参数是时间的格式,并且指定了一个默认值.然后下面通过 app.add_ template_filter,将datetimeformat函数注册成了过滤器,并且这个过滤器的名字,叫做dformat
模板文件中,就可以这样类似这样使用了:{{article.pub_date | dformat}}

五、控制语句(基于jinja2)

def control_statement():
    age = 18
    books = [{"name":"三国演义","author":"罗贯中"},{"name":"水浒传","author":"施耐庞"}]
return render_template("control.html", age=age, books=books)

--control.html中:
1、判断

<body>
{% if age>18 %}
    <div>大于18</div>
{% elif age==18 %}
    <div>等于18</div>
{% else %}
    <div>小于18</div>
{% endif %}
</body>

2、遍历

{% for book in books %}
<div>图书名称: {{ book.name }},图书作者: {{ book.author }}</div>
{% endfor %}

六、模板继承(基于jinja2)-HTML继承

1、引用base.html模板,在顶部引用

{% extends "base.html" %}

2、需要重写的地方,定义成block:title、head、body、footer,可以在字模板重新写

{% block title %}首页{% endblock %}
{% block title %}
color: red;
{% endblock %}

七、加载静态文件(基于jinja2)

1、一个网页中,除了HTML代码以外,还需要CSS、JavaScript和图片文件才能更加美观和实用。静态文件默认是存放到当前项目的static文件夹中,如果想要修改静态文件存放路径,可以在创建Flask对象的时候,设置 static folder 参数:

app = Flask(__name__, static_folder = 'C:\static')

2、在HTML模板文件中,可以通过url_for加载静态文件:

<link href="{{url_for('static',filename = 'about.css')}}">

八、Flask-SOLAlchemy基本使用

# 用到的包
pip install SQLAlchemy
pip install flask-sqlalchemy

1、连接MySql

使用Flask-SQLAlchemy 操作数据库之前,要先创建一个由Flask-SOLAlchemy提供的SQLAlchemy类的对象。在创建这个类的时候,要传入当前的app。然后还需要在app.config中设置SOLALCHEMY_DATABASE_URI,来配置数据库的连接

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
# config文件中:
# MySQL所在的主机名
HOSTNAME = "127.0.0.1"
# MySQL监听的端口号,默认3306
PORT = 3306
# 连接MySOL的用户名
USERNAME = "root"
# 连接MySQL的密码
PASSWORD = "root"
# MySQL上创建的数据库名称
DATABASE = "database_learn"
app.config['SQLALCHEMY_DATABASE_URI'] = f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8"

db=SQLAlchemy(app)

with app.app_context():
    with db.engine.connect() as conn:
        rs = conn.execute("select 1")
        print(rs.fetchone()) #(1,)

@app.route('/')
def hello_world():
    return 'Hello World!'
 
if __name__ == '__main__'
    app.run()

2、ORM模型:

对象关系映射(Object Relationship Mapping),简称ORM,是一种可以用Python面向对象的方式来操作关系型数据库的技术,具有可以映射到数据库表能力的Python类我们称之为ORM模型。
(1)一个ORM模型与数据库中一个表相对应,ORM模型中的每个类属性分别对应表的每个字段,ORM模型的每个实例对象对应表中每条记录
(2)ORM技术提供了面向对象与SOL交互的桥梁,让开发者用面向对象的方式操作数据库
(3)优势:
--开发效率高:几乎不需要写原生SQL语句,使用纯Python的方式操作数据库,大大的提高了开发效率
--安全性高:ORM模型底层代码对一些常见的安全问题,比如SOL注入做了防护,比直接使用SOL语句更加安全
--灵活性强:Flask-SOLAlchemy底层支持SQLite、MySQL、Oracle、PostgreSOL等关系型数据库,但针对不同的数据库,ORM 模型代码几乎一模一样,只需修改少量代码,即可完成底层数据库的更换
(4)例子-创建一个表:

class User(db.Model):
    __tablename__ = "user"
    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)
    # 相当于sql: insert into user(username,password) values(法外狂徒张三,1111111);
    
with app.app_context():
    db.create_all

3、ORM增删改查数据

(1)新增数据:

@app.route("/user/add")
def add_user():
    # 1.创建ORM对象
    user = User(username="法外狂徒张三",password='111111')
    # 2.将ORM对象添加到db.session中
    db.session.add(user)
    # 3.将db.session中的改变同步到数据库中
    db.session.commit()
    return "用户创建成功!"

(2)查询数据:

ORM 模型都是继承自db.Model,db.Model内置的query属性上有许多方法,可以实现对ORM模型的查询操作。query上的方法可以分为两大类,分别是过滤方法以及提取方法:

提取方法:

query.all():获取查询结果集中的所有对象,是列表类型
query.first():获取结果集中的第一个对象
query.one():获取结果集中的第一个对象,如果结果集中对象数量不等于 1,则会抛出异常
query.one_or_none():与one类似,结果不为1的时候,不是抛出异常,而是返回None
query.get(pk):根据主键获取当前ORM模型的第一条数据
query.exists():判断数据是否存在
query.count():获取结果集的个数

过滤方法:

query.filter():根据查询条件过滤
query.filter_by():根据关键宁参数过滤
query.slice(start,stop):对结果进行切片操作
query.limit(limit):对结果数量进行限制
query.offset(offset):在查询的时候跳过前面offset条数据
query.order_by():根据给定字段进行排序
query.group_by():根据给定字段进行分组
除了直接使用= =、=外,还可以使用以下常用的过滤条件进行过滤,这些过滤条件通过flter方法实现
like:users-User.query.filter(User.username.like("张"))
in:users-User.query.filter(User.username.in_(["张三","李四","王五"]))
not in:users-User.query.filter(~User.username.in_(['张三'])
is null:users=-User.query.filter(User.username.is_(None))
is not null:users =User.query.filter(User.username.isnot(None))
and:users=User.query.filter(and_(User.username"张三",User.id<10))
or:users=User.query.filter(or_(User.username
"张三",User.id<10))

@app.route("/user/query")
def query_user():
    # 1.get查找:根据主键查找
    users = User.query.get(1)
    # 取user中所有数据
    users = User.query.all()
    # 获取第一条数据
    user = User.query.first()
    print(f"{user.id}: {user.username}-{user.password}")
    # 2.filter_by查找
    # Query:类数组
    users = User.query.filter_by(username="张三")
    for user in users:
        print(user.username)
    return "数据查找成功!"

(3)修改数据:

@app.route("/user/update")
def update_user():
    user= User.query.filter_by(username="张三").first()
    user.password = "222222"
    db.session.commit()
    return "数据修改成功!"

(4)删除数据

# 删除单条数据
user= User.query.get(1)
db.session.delete (user)
db.session.commit()
# 删除多条数据:通过BaseQuery上的delete方法
User.query.filter(User.username.contains("张三")).delete(synchronize_session=False)
db.session.commit()
@app.route("/user/delete")
def delete_user():
    user= User.query.get(1)
    db.session.delete (user)
    db.session.commit()
    return "数据删除成功!"

4、表关系:一对一、一对多(多对一)、多对多

(1)外键:在Flask-SQLAchemy 中支持创建ORM模型的时候就指定外键,创建外键是通过db.ForeignKey实现的
例如:创建一个Article表,有一个author_id字段,通过外键引用user表的id字段

class Article(db.Model):
    __tablename__="article"
    id=db.Column(db.Integer,primary_key=True,autoincrement=True)
    title=db.Column(db.string(200),nullable=False)
    content=db.Column(db.Text,nullable=False)
    author_id=db.Column(db.Integer,db.ForeignKey("user.id"))

以上代码,除了添加常规title、content属性外,还增加了一个autbor_id,author_id通过db.ForeignKey(“user.id”)引用了user表的id字段。注意author_id因为引用user表的id字段,所以他的类型必须跟user表的id字段一致
(2)为了达到操作ORM对象就跟操作普通Pytho对象一样,Flask-SQLAlchemy 提供了db.relationship来引用外键所指向的那个ORM模型。在以上的Article模型中,添加dbrelationiship:

class Article(db.Model):
    __tablename__="article"
    id=db.Column(db.Integer,primary_key=True,autoincrement=True)
    title=db.Column(db.string(200),nullable=False)
    content=db.Column(db.Text,nullable=False)
    author_id=db.Column(db.Integer,db.ForeignKey("user.id"))
    author=db.relationship("user")

添加了一个author属性,这个属性通过db.relationship与User模型建立了联系,以后通过Article的实例对象访问author 的时候,比如article.author,那么Flask-SQLAlchemy会自动根据外键author_id从user表中寻找数据,并形成User模型实例对象
如通过创建Article对象,并通过访问Article实例对象上的author属性来关联User对象:

@app.route('/article/add')
def article_add():
    user = User.query.first()
    article = Article(title="aa",content="bb",author=user)
    db.session.add(article)
    db.session.commit()

(3)为了实现双向关系绑定,我们还需要在 User模型上添加一个dbrelationship 类型的articles 属性并且在 User模型和Article模型双方的dbrelationship上,都需要添加一个 back populates 参数,用于绑定对方访问自己的属性:

class User(db.Model):
    __tablename__ = "user"
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    username = db.Column(db.string(100))
    password = db.Column(db.String(100))
    articles = db.relationship("Article",back_populates="author")
    
class Article(db.Model):
    __tablename__  = "article"
    id = db.Column(db.Integer,  primary_key=True,autoincrement=True)
    title =  db.Column(db.string(200),nullable=False)
    content = db.Column(db.Text,nullable=False)
    author_id = db.Column(db.Integer,db.ForeignKey("user.id"))
    author = db.relationship("user",back_populates="articles")

在User 端绑定了articles 属性后,现在双方都能通过属性直接访问到对方了:

user = User.query.first()
for article in user.articles:
    print(article.title)

(4)还可以通过只在一个模型上定义db.relationship类型属性,并且传递backref参数,来实现双向绑定
backref:会自动的给User模型添加一个articles的属性,用来获取文章列表

author = db.relationship("User",backref="articles")

(5)级联操作
级联操作(Cascade)是在操作某个对象的时候,相关联的对象也会进行对应的操作。在数据库层面的级联操作包括级联删除,级联更新等。Flask-SQLAlchemy 提供了比数据库级更强大的级联操作,定义级联操作是通过在 db.relationship 传递 cascade 参数实现的,这个参数的值可以为all、save-update、merge、refresh-expire、expunge、delete中的一个或者是多个,如果是多个,则通过英文逗号隔开,比如”save-update,delete”。谁设置了cascade 参数,谁就是父表,父表数据发生变化,相关联的从表也会执行相应操作

class Category(db.Model):
    __tablename__ = "category"
    id = db.Column(db.Integer,primary_key-True,autoincrement=True)
    name = db.Column(db.string(100))
    newses = db.relationship("News",back_populates="category")

class News(db.Model):
    __tablename__ = "news"
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    title = db.Column(db.string(100))

(6)ORM模型映射成表的三步:

# 1.flask db init:这步只需要执行一次,初始化
# 2.flask db migrate:识别ORM模型的改变,生成迁移脚本
# 3.flask db upgrade:运行迁移脚本,同步到数据库中

我之前报错:Fatal error in launcher: Unable to create process using '"d:\python36\python.exe" "D:\Python\Scripts\flask.exe" flask db init': ???????????
指定python能解决,运行时加python -m ,如:python -m flask db init

九、邮件

1、pip install flask-mail

十、常用方法:

1、render_template:返回HTML模板
2、用到的包:
pip install flask
pip install SQLAlchemy:数据库
pip install flask-sqlalchemy:数据库
pip install flask-mail:邮件
pip install email_validator:邮件,校验器

未完待续。。