likes
comments
collection
share

flask基本功能实现(一篇就够)

作者站长头像
站长
· 阅读数 37

引言

哈喽大家好,这篇文章是我flask入门差不多一个月的时间搞出来的,基本上能让你的网站功能差不多齐全,具体效果请看panwy.tech(我的网站)话不多说,开始吧

开始

要有基本功能,你需要导入这几个包:

from flask import Flask, render_template, Response, request, session, redirect
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField
from wtforms.validators import DataRequired
import sqlite3

(sqlite3自选)

然后初始化

app = Flask(__name__)
# flask_wtf设置
app.config["SECRET_KEY"] = "自己填"
# flask session设置
app.secret_key = "自己填"

启动

首先,你需要在当前app.py下创建templates和static文件夹(这里用pycharm professional的就很香,自动帮你创建) flask的语法长这样:

@app.route("/")
# 路由路径
def hello_world():
    return render_template("index.html")
# 这里的函数名字每一个别重复

render_template后的文件就是当你访问页面时会返回的。(在此教程中,我不会显示很多html,除非是必要部分)

然后运行

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=80, debug=True)

此时访问localhost,就能看到你index.html中的东西了

但这只是初步,如果不加其他东西,那就不是web框架了,下一步就是整活!(bushi)

网站标配

如果你看到了访问时flask输出的日志,你就会看到

127.0.0.1 - - [日/月/年 时间] "GET /favicon.ico HTTP/1.1" 404 -

这就说明你没有设置favicon,那应该如何优雅的设置favicon呢?

首先自己搞一个发favicon,放到static文件夹下面,

@app.route('/favicon.ico')
def favicon():
    return app.send_static_file("favicon.ico")

就好了,而且不用在每一个页面中添加

 <link rel= "shortcut icon" href= "/favicon.ico" >

岂不优雅乎?

还有一个就是404页面的返回

基本上,网站都会有一个独特的404页面,那你总不可能把每一个页面都遍历一遍吧,况且这也不可能,因此flask也有这个功能

@app.errorhandler(404)
def errorhandler(e):
    return render_template("404.html"), 404
# 那个e我也不知道为啥,但是这么写就完事了

最后是一个方法,之前遇到的问题(如何返回视频)

def video_stream(file):
    with open(file, 'rb') as f:
        data = f.read(5120)
        while data:
            yield data
            data = f.read(5120)
@app.route("/ad")
def rick_roll():
    return Response(video_stream('rick.mp4'), mimetype='video/mp4')

5120是每次加载5120字节(就是那个灰色的进度条,自己挑)

web框架的独特

传参

接下来要讲的是传参,也就是从flask后端传到html网页前端的过程。

以访问用户界面为例。

如果你想要在访问/user/pwy时返回的标题是pwy,访问/user/ybn时返回ybn,就需要传参了,虽然js可能也可以,但是这样不是更加厉害吗?doge

@app.route("/user/<name>")
def user(name):
    return render_template("user.html", username=name)

而在user.html中的title标签,要这么写

<title>{{ username }}</title>

就好了。

在app.route中,小于号name大于号(markdown转义的问题) 表示如果访问/user后的路由,就会在方法中传入这个路由字符串,成为变量,而username=name则表示html中的username会替换为python中的name变量。

flask-wtf

flask-wtf是一个第三方的flask表单库,里面有许多不同类型的提交内容,这里用到了StringField和PasswordField,作为一个初步的功能

在设置路由之前,先“设计”好表单

class Login(FlaskForm):
    username = StringField('用户名')
    password = PasswordField('密码')

当然,也可以加上必填字段的条件

class Login(FlaskForm):
    username = StringField('用户名', validators=[DataRequired()])
    password = PasswordField('密码')

在调用前,需要知道get和post请求

get请求是获取页面,由服务器到用户

post请求是提交(表单),由用户到服务器

默认情况下,flask只允许get,如果用post,会显示504method not allowed,所以要设置允许的方法

# methods设置方法
@app.route('/login', methods=['GET', "POST"])
def login():
    # 获取Login表单
    form = Login()
    # 如果是get请求做出的判断
    if request.method == 'GET':
        return render_template('login.html', form=form)
        # 传入表单到html
    #post请求的处理
    # 获取数据
    usn = form.username.data
    pwd = form.password.data
    if usn == "admin" and pwd == "123"
        return "密码正确"
    else:
        return "密码错误"

然后是前端的传入

<form method="post" action="/login">
    {{ form.csrf_token}}
    {{ form.username.label }} {{ form.username }}
    {{ form.password.label }}{{ form.password }}
    <button type="submit" class="btn btn-primary btn-block btn-large">登录</button>
</form>

如果你用的是别的路径或者是单独设置了一个路径专门用来接受表单,记得把action中的/login改掉

奥对了,顺便说一声,如果你找的模板在input上有class之类的美化,可以这样: {{ form.username(class=xxx, id=xxx) }}

cookie

cookie,不用多说了吧,直接开始。

# 写入
session['username'] = usn
# 读取
session.get('username')

然后加入到刚才的python代码中

if usn == "admin" and pwd == "123"
        session['username'] = usn
        return "密码正确"

有了cookie,就可以保持登录了

@app.route("/profile")
def profile():
    username = session.get('username')
    if username is None:
        return "你没登陆吧"
    return render_template("profile.html", username=username)

html我就不给了,反正都知道的

扩展(连接sqlite3)

本人有幸学过一句sqlite语句,那就浅浅连接一下,这也可以更方便存储用户数据

在app.py的目录下新建一个sqlite文件,里面新建一个表,具体内容长这样(仅供参考)

flask基本功能实现(一篇就够)

app.py代码:

import sqlite3
login = sqlite3.connect("文件名", check_same_thread=False)
# check_same_thread防止调用的时候报错
cur = login.cursor()

由于执行sql语句是“临时的”,且更改数据要实时读取,因此execute(执行语句的函数)放在路由的函数里面

@app.route('/login', methods=['GET', "POST"])
def login():
    form = Login()
    if request.method == 'GET':
        username = session.get('username')
        return render_template('login.html', form=form)
    usn = form.username.data
    pwd = form.password.data
    table = cur.execute("""select * from login""").fetchall()
    # sql语句筛选表,login是表名
    for c in table:
        if c[0] == usn and c[1] == pwd:
            # 开始遍历
            session['username'] = usn
            return "密码正确"
    return "密码错误"

杂项

关于模板链接的引用方法

如果你用的是应用其他文件夹的内容(比如link或者href写的是/css/css.css),其实不用担心麻烦。

在static文件夹下面新建一个index文件夹(便于区分),里面把css之类的文件夹放进去。在html中,将/css/css.css替换为/static/css/css.css(前面加一个/static)就好了,不需要你额外在app.py里面加东西。u1s1这个功能蛮方便的。

flask运行时的warning是咋回事?

如果你是直接允许flask,会有这一行

WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.

(可能都见怪不怪了hhh)

不过这句话其实可以解决的,或者说它本来就应该用来解决。

方法也很简便,导入

from gevent import pywsgi

末尾把app.run替换为

server = pywsgi.WSGIServer(('0.0.0.0', 80), app)
server.serve_forever()

此时再次允许,会啥也没有,但访问仍然会输出日志(没有debug模式,毕竟是部署模式了)

结尾

那就差不多这样,希望能对你的flask技术有帮助。(后面可能会再加一点东西)别忘了看看我的网站panwy.tech !!!(我里面贴了github源码链接,可以去看看,这篇文章其实差不多就是对那个的讲解