Flask基础及常见问题整理

news2024/12/29 12:54:46

一、Flask框架介绍

使用python开发后端,目前主流的框架就是Flask和Django。其中,Flask是一款轻量级的Python web框架,有以下主要特点:

1. 简单易用

Flask很简单易用,可以快速上手开发web应用。它只依赖Werkzeug和Jinja2两个库,没有象Django那样的重量级复杂的功能。

2. 灵活

Flask非常灵活,可以适用于不同的项目规模。从简单的"Hello World"到大型项目都可以使用Flask开发。并且它可以与更多的flask扩展结合,实现更丰富的功能。相对来讲,Django只适合较大的工程。

3. Pythonic

Flask使用Python语言开发,遵循Pythonic的设计理念,语法优雅简洁,具有很强的可读性。这使得Flask非常适合学习和理解。

4. RESTful

Flask天生支持RESTful风格的web服务开发。HTTP一级支持,简单的URL规则等使其非常适合构建REST API。

5. 扩展性强

Flask最重要的一个特点就是拥有丰富的扩展,几乎涵盖了web开发所有的功能,如:ORM(Flask-SQLAlchemy)、表单验证(Flask-WTF)、文件上传(Flask-Uploads)、用户认证(Flask-Login)等。这些扩展可以根据需要很容易集成到Flask应用中。需要什么插件,就安装什么插件。

6. 部署方便

Flask的应用十分简单,甚至一个py文件就行。它支持与各种Web服务器兼容,如WSGI服务器、Nginx和uWSGI等。

7. 社区优秀

Flask拥有庞大的社区,官方文档资料也比较齐全。几乎所有的问题都可以在网上找到答案。

所以,总的来说,Flask是一个简单、灵活、易于理解、可扩展性强的Python web框架。它适用于学习、 小型项目以及复杂项目。具有非常优秀的社区资源和生态环境。

二、RESTFul协议特点

1. 基于HTTP

RESTful API基于HTTP协议,使用HTTP方法为资源定义操作。如GET用于读取,POST用于创建,PUT用于更新,DELETE用于删除等。有的API接口,无论是读取还是更新,都统一使用POST方法,而把实际的动词包含在URL里,如'/data/delete'。

2. 无状态

RESTful API是无状态的,它不存储任何客户端上下文信息。每个请求必须包含请求所需要的所有信息,服务器根据请求进行响应。

3. 层次结构

RESTful API使用统一的接口访问命名空间中的所有资源。这些资源可以被层次化,形成资源的树形结构。

4. 使用URL定位资源

每个资源都有一个唯一的URL来指定和定位,这一点和文件夹路径原理是一样的。

5. 可缓存

RESTful API响应可以是可缓存的,这可以提高效率和性能。缓存可以存在于服务器端、客户端或代理服务器。这一点对于频繁请求某一资源时很有帮助。

6. 统一接口

 RESTful API将所有资源通过统一的接口来访问和操作。这简化了整个系统。

7. 跨语言兼容

RESTful API返回的通常为JSON或XML格式。这使其对各种语言和平台更易于实现和兼容。

REST是一种优秀的开发思路和规范,但我们在实际开发时也要辩证来看。规范和通用的东西必然在灵活性上有所不足。如果我们开发的是对外的、通用的接口,那么REST是一个好的选择。但如果这个接口只对内部提供,则不必严格按照REST协议来。因为实际的业务往往是复杂的、具体的和相对固定的。那么针对性地提供一些接口,会让前端开发(调用者)更容易。某种程度,也可以减少一定的http请求次数。如某个页面有几十个数据需要请求,按照REST风格来可能需要请求几十个接口,而我们可以设计一个统一接口将全部信息返回(有点夸张了)。

三、路由

1、路由的概念

百度百科的解释是:“路由(routing)是指分组从源到目的地时,决定端到端路径的网络范围的进程”。在TCP/IP协议里,路由器的工作就是将不同的信息根据ip地址进行分发。而在web开发中,概念也基本一致。即将前面提到的url与资源进行一种映射,请求相应的url则获取对应资源。而建立这种映射的过程就叫注册路由。

2、两种路由注册方式

from flask import Flask

app = Flask(__name__)


# 方法一
@app.route('/hello')
def hello():
    return 'hello world'


if __name__ == '__main__':
    app.run('0.0.0.0', 5555)

 第一种方法是利用了python装饰器的特性,route方法内部仍然是调用add_url_rule。本质是一样的,只是装饰器看起来更优雅。

关于装饰器的解释可以参考下文Python 装饰器_function databaseerrorwrapper.__call__.<locals>.in_Jiangugu的博客-CSDN博客

from flask import Flask

app = Flask(__name__)


def hello():
    return 'hello world'


# 方法二
app.add_url_rule('/hello', view_func=hello)

if __name__ == '__main__':
    app.run('0.0.0.0', 5555)

                                

四、Request请求对象

以百度搜索关键词python为例,可以通过后台查看请求对象包含的信息

 

可以看到,虽然我们只输入了一个python,但实际的请求包含了很丰富的信息。如请求头里包含的请求地址、方法 ,请求体里包含的关键字等。在一些需要登陆的网站,往往还需要携带cookies。本文主要还是讲解利用flask搭建后端,主要作为响应端。即如何响应请求,关于更多request的介绍请参考下文。

Python 网络开发基础之Requests_request是技术还是库_Jiangugu的博客-CSDN博客

五、Response响应对象

响应对象和请求对象一样,除了“内容”部分,还会包含诸多其他信息。常见的如content-type、status_code。在flask里,必须指定的是内容部分,其余均有默认值。

1、content-type

默认的content-type是html,那么返回的字符串就会按照html的格式去解析,因此前端显示为空。

@app.route('/test')
def test():
    return '<html></html>'

如果想显示这段文本,则手动指定content-type即可

@app.route('/test')
def test():
    header = {
        'content-type': 'text/plain'
    }
    return '<html></html>', header

 

返回一个网页的示例

@web.route('/square/<p>', methods=['GET'])
def square(p):
    """
    :param p:
    :return: 返回的是一个html
    """
    return render_template('test.html', result=int(p)**2)

 这是前端部分(样式CSS和脚本JS没有展开,本文主要讲解后端和接口)。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>'测试网页'</title>
</head>
<body>
<div>
    <p style="color: red">计算结果是:{{ result }}</p>
</div>
</body>
</html>

 

 而对于API来说,content-type为'application/json',即要求调用者按照json格式去解析。

2、状态码

常见状态码包括200(请求成功)、301(重定向)、404(未找到资源)、500(服务器内部错误)。这里需要强调的是,状态码只是一种约定。你完全可以约定请求成功是404,只要事先和请求方约定好。

虽然浏览器报错,但内容仍正常显示。此外,在接口开发中,可能出现的情况会很多。仅有的几个状态码一般都是不够用的。往往会在内容content里再约定一个如status这样的变量,约定1是成功,2是没有权限,3是参数不够,4是数据范围超出……

from flask import Flask
import json
app = Flask(__name__)


@app.route('/test/<nums>')
def test(nums):
    dt = nums.split(',')
    header = {
        'content-type': 'application/json',
    }
    if len(dt) > 10:
        return json.dumps({'status': 4, 'msg': '数据长度不能超过10'}), 500, header
    else:
        return json.dumps({'status': 1, 'result': 111}), 200, header


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

 

六、表单

除了URL里可以携带参数,还有一种常见的传参方式就是通过表单,如登录和注册页面填写的账号、密码等信息。后端如何接收这些信息呢?

<html>  
	<head>   
		<title>测试网页</title>
		<link rel="stylesheet" type="text/css" href="static/login.css"/>
		<link rel="shortcut icon"
          href="{{ url_for('static', filename='pics/logo.png') }}">
	</head>  
	<body>    
		<div id="main">
			<div id="top">
				<img src={{url_for('static', filename='pics/pure_logo.png')}}  id="logo">
			</div>
			<div id="bottom">
				<form  method="POST">
					<p class="titleofinput">用户名: </p>         
					        
					<input type="text" name="username" class="input" autocomplete="off" placeholder="请输入用户名" required>     
					          
					<p class="titleofinput">密码: </p>         
					         
					<input type="password" name="password" class="input" autocomplete="off" placeholder="请输入密码" required>       
					<br>          
					<button type="submit" id="submit">登录</button>
				</form> 
			</div>
		</div>
	</body>
</html>

这个简单的登录界面示例代码中,输入用户名和密码使用的是<input>标签且存在于<form>里。而它们都有一个name属性,因此后端可以通过这个属性获得对应传递过来的值。

from flask import request, url_for, redirect, render_template
from flask_login import login_user
from model.user import User
from . import web


@web.route('/login', methods=['GET', 'POST'])
def login():
    username = request.form.get('username')
    password = request.form.get('password')
    if request.method == 'POST':
        # 自定义的user模型,将具体的校验方法封装其中,也可以直接粗暴地写在这里
        user = User.query.filter_by(username=username).first()
        if user and user.check_password(password):
            # 将用户登录票据写入客户端cookies, remember开启默认保存365天
            login_user(user, remember=True)
            return redirect(url_for('web.do'))
        else:
            return '用户名或密码错误'

    return render_template('login.html')

七、其他零散知识点

1、IP地址

我们的app在绑定地址时,可以写网卡的实际地址,如192.168.0.111(固定地址,地址改变时需同步更改),也可以写127.0.0.1(只允许本机访问),还可以写0.0.0.0。一般我们在开发的时候,随便写哪个都可以,因为都是本机访问且地址不会变。但如果地址可能会变,同时正式部署后要允许其他计算机访问,就只能写0.0.0.0。

2、端口

原则上,端口可以在1~65535范围内任意指定,只要不与已有的端口冲突即可。如22是ssh通讯端口,3306是数据库端口。而web端口默认是80,即使用默认端口时,浏览器访问可以不指定端口。

3、调试模式

后端开发是一个交互性很强的工作,需要一边调整一边看结果。因此,如果每次修改代码都需要重启应用的话会很浪费时间。在flask里只需要打开调试模式即可实现类似监听的功能,代码的修改能立刻应用。

app.run('0.0.0.0', 8000, debug=True)

4、参数配置

一个优秀的web服务,离不开诸多参数配置。如前面提到的端口号、调试模式等。实际上很多代码工程都需要配置参数,而一个好的参数配置需要具备“可读性强”,“易修改”等特点。因此,最好的方式就是在一个统一的地方,统一对参数进行定义和赋值,在整个工程其他地方使用定义的变量名。这里有两种方式推荐,其一是配置系统环境变量,然后在代码里通过os.environ.get('变量名')。第二种方法是创建一个配置文件,如config.py,在这个文件里配置一些参数,如DEBUG=True,注意变量名需全部大写

# 加载配置模块
app.config.from_object('config')
# 调用相应配置参数
app.run('0.0.0.0',  debug=app.config['DEBUG'])

5、重定向

有一些资源暂时没有或不想让别人访问,除了抛出404,还可以重定向。即建议请求者重新请求一个地址。

@app.route('/test')
def test():
    header = {
        'content-type': 'text/plain',
        'location': 'https://www.baidu.com'
    }
    return '<html></html>', 301, header

6、传参

(1)多参数传参

我们在上面的案例中,参数是直接跟在url后的。那是因为参数只有一个,不太容易引起误解。如果查询参数较多,一般可以使用以下方式

from flask import request
import json


@app.route('/plus')
def plus():
    a = request.args['a']
    b = request.args['b']
    header = {
        'content-type': 'application/json',
    }
    return json.dumps({'status': 1, 'result': int(a) + int(b)}), 200, header

 

(2)数组传参

在调用API接口时,有时会需要传递一个较大的数据。这时候就不适合将数据作为查询参数添加到url里。一方面会导致url可读性较差,同时,url也会有长度限制(因浏览器,服务器等不同,一般限制几千个字符)。此时,可以将数据放到请求体里。

from flask import Flask, request
import json
app = Flask(__name__)


@app.route('/test/')
def test():
    dt = request.json['data']
    header = {
        'content-type': 'application/json',
    }
    if len(dt) > 10:
        return json.dumps({'status': 4, 'msg': '数据长度不能超过10'}), 400, header
    else:
        return json.dumps({'status': 1, 'result': sum(dt)}), 200, header


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

 7、Cookie

由于http请求是没有记忆的,每次请求都是独立没有上下文关联的。但有时我们需要这种上下文关联,比如记录登录信息、购物网站的购物车、搜索记录等。记录这种信息的载体就是Cookie,它是由服务器生成并写入访问客户端的。客户端在下一次的访问中就会携带该信息,以便继续对话。Cookie是以键值对的形式存储的,除了key-value的信息,一般还包括允许访问的域名、有效期等信息。使用flask框架的服务可以通过以下方式生成Cookie

from flask import make_response

@app.route('/')
def index():
    # 这里快速构造了一个response对象,和前面的一样
    resp = make_response('Hello')
    # 有效期1000秒
    resp.set_cookie('username', 'john', 1000)
    return resp

 访问相应的视图函数,此时浏览器已经被写入Cookie。

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/682335.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Uniformer 训练心得

这是我配环境进行训练的第一个程序&#xff0c;遇到了很多问题&#xff0c;在这里总结一下 首先是配环境 按照官方代码进行配&#xff0c;我跑的是uniformer中的object detection 官方github 在这里我遇到的问题 配mmdetection时总是代码有标红错误&#xff0c;注意&#xf…

卡萨帝:领跑者的代价和陪跑者的聪明

一台设备可以卖1.2亿欧元&#xff0c;而世界上只有一家公司可以生产&#xff1b;占据市场80%份额&#xff0c;在高端光刻机领域处于垄断地位&#xff1b;看不见任何竞争对手。 看完这几个信息&#xff0c;相信有些人已经猜到是何方神圣了&#xff0c;这正是荷兰的光刻巨人ASML…

为什么单击并按住标题栏,程序运行得更快?

有时候&#xff0c;人们会发现这样一个怪异现象&#xff1a;如果在执行一项长时间运行的任务的时候&#xff0c;在标题栏按下鼠标&#xff0c;这个时候&#xff0c;会发现程序运行的更快了一些。 这件奇怪的事情通常是发生在这样一种场景&#xff1a;当程序花费太多时间更新其…

手机录屏录音不用愁,这些方法无需ROOT就能内录声音!

现在不少人喜欢用视频分享生活&#xff0c;除了外拍视频&#xff0c;或多或少也有需要内录视频的时候&#xff0c;比如录个操作步骤啊、游戏视频啊&#xff0c;或者录个网课、录首歌啥的… 之前也有不少粉丝留言问过我这个问题&#xff0c;所以今天就打算来和大家简单分享一下…

JSP自定义标签【上】

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于自定义标签的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.什么是标签 二.什么是自定义标签…

国产骨传导耳机哪个牌子好,分享几款表现不错的国产骨传导耳机

骨传导耳机是一种新兴的耳机技术&#xff0c;其原理是将声音转化为不同频率的机械振动&#xff0c;通过人的颅骨、骨迷路、内耳淋巴液、螺旋器、听觉中枢来传递声波&#xff0c;不通过鼓膜&#xff0c;不入耳&#xff0c;不影响耳朵的听觉。听音乐是人们生活中不可缺少的一部分…

二叉树OJ题:LeetCode--965.单值二叉树

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下LeetCode中第965道二叉树OJ题&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; 数据结构与算法专栏&#xff1a;数据结构与算法 个 人…

python旅游推荐系统-计算机毕设 附源码82884

旅游推荐系统 摘 要 随着社会的快速发展和人们生活水平的不断提高&#xff0c;旅游已逐渐成为人们生活的重要组成部分&#xff0c;用户能够获取旅游信息的渠道也随信息技术的广泛应用而增加。大量未经过滤的信息在展示给用户的同时&#xff0c;也淹没了用户真正感兴趣的信息。为…

二十三种设计模式第十一篇--桥接模式

好久没写博客了&#xff0c;自从进入6月份&#xff0c;毕业季&#xff0c;全是在忙毕业的事情&#xff0c;都没怎么学习代码软件工程知识了&#xff0c;这二十三种设计模式还是得学完哈&#xff01;持之以恒&#xff0c;我本来为了学这二十三种设计模式的初衷是为了顺利度过软考…

Azkaban的安装教程

Azkaban的安装教程 文章目录 Azkaban的安装教程写在前面集群模式安装下载安装包上传 **tar** 包解压配置 **MySQL**配置 **Executor Server**编辑 azkaban.properties同步 azkaban-exec到所有节点启动 executor server激活 executor **配置** **Web Server**编辑 azkaban.prope…

短视频seo源码搭建技术分享

一、目录及主要文件说明 bootstrap目录&#xff0c;存放框架引导及启动文件&#xff0c;非底层改动&#xff0c;无需修改。其中的functions.inc中可以定义一些全局函数error目录&#xff0c;存放404、500等常见错误模板文件&#xff0c;非需勿动includes目录&#xff0c;drupal…

SpringBoot 如何使用 JProfiler 进行性能测试

SpringBoot 如何使用 JProfiler 进行性能测试 在 SpringBoot 应用程序中&#xff0c;我们可以使用 JProfiler 进行性能测试。JProfiler 是一款专业的 Java 性能分析工具&#xff0c;可以帮助我们识别和解决应用程序的性能问题。使用 JProfiler 可以让我们更加准确地测试代码的…

C语言进阶教程(字符串深入)

文章目录 前言一、字符数组赋值注意事项二、混淆点三、字符串字面量和字符数组的区别四、字符串长度总结 前言 其实在C语言中是没有真正的字符串的&#xff0c;在C语言中字符串都是使用字符数组来完成的。 一、字符数组赋值注意事项 在C语言中&#xff0c;字符数组&#xff…

[RocketMQ] Producer生产者启动源码 (五)

DefaultMQProducer的关系图: 文章目录 1.创建DefaultMQProducer实例2.start启动生产者2.1 getOrCreateMQClientInstance获取或者创建MQClientInstance2.2 registerProducer注册生产者2.3 start启动MQClientInstance2.4 startScheduledTask启动各种定时任务2.4.1 updateTopicRou…

【Linux】切换内核版本(Centos)

1.查看服务器已安装的所有内核版本 awk -F\ $1"menuentry " {print i " : " $2} /etc/grub2.cfg0 : CentOS Linux (3.10.0-1160.83.1.el7.x86_64) 7 (Core) 1 : CentOS Linux (3.10.0-1160.80.1.el7.x86_64) 7 (Core) 2 : CentOS Linux (3.10.0-1127.el7.…

求最小函数依赖集(例题讲解)超详细,易理解

在关系R<U,F>中&#xff0c;UABCDEG F{BG->C&#xff0c;BD->E,DG->C,ADG->BC,AG->B,B->D} 先进行第一大步&#xff1a; 先看右边&#xff1a; 如果有BG->C,G-->C,因为单G就可以推出C了就不需要BG--->C了&#xff0c;可以把BG--->C这个…

Segment Anything Model(SAM)

Segment Anything Model&#xff08;SAM&#xff09;是Facebook Research近来开源的一种新的图像分割任务、模型。Segment Anything Model&#xff08;SAM&#xff09;可以从输入提示&#xff08;如点或框&#xff09;生成高质量的对象掩模&#xff0c;并可用于生成图像中所有对…

1、一条 SQL 查询语句是如何执行的?

基础篇 第一课、一条 SQL 查询语句是如何执行的&#xff1f; 下面是 MySQL 的基本架构示意图&#xff0c;从中可以清楚地看到 SQL 语句在 MySQL 的各个功能模块中的执行过程。 大体来说&#xff0c;MySQL 可以分为 Server 层和存储引擎层两部分。 Server 层包括连接器、查询缓存…

AI近十年盘点:纵览AI发展历程,探寻AI未来走向

编者按&#xff1a;当我们回顾过去十年的人工智能发展历程时&#xff0c;可以看到一场现在还正在进行的变革&#xff0c;对我们的工作方式、商业运营模式和人际交往行为都产生了深远的影响。从2013年的AlexNet到变分自编码器&#xff0c;再到最近的生成式大模型&#xff0c;人工…

Vue 2 - 常见面试题汇总大全

文章目录 一 基础知识1.vue 的生命周期1-1 钩子函数1-2 钩子函数的使用方法1-3 父子组件生命周期构造函数执行顺序 2 v-show 与 v-if v-for2-1.v-show 与 v-if 的区别2-2 v-if 和v-for的优先级 3.组件通信有哪些方式&#xff1f;4 computed和watch &#xff0c;有什么区别4-1.c…