1_初步了解和试运行

1_初步了解和试运行

  • 前言

    本人原来使用的是Flask框架(公司在用),掌握的也不是很好,处于简单会用的层面。然后,公司想转用FastAPI,毕竟能火起来的技术自有可取之道,在此记录自己的学习过程。
    学习过程中,主要观看了以下学习视频:

  • 目录

    • 搭建虚拟环境

    • 安装FastAPI

    • 试运行Hello World

    • 试用模版引擎

    • 试用表单提交数据

    • 试用表单上传文件

  • 虚拟环境(非必须)

    虚拟环境是啥这里就不加以解释,简单理解就是每个项目有个独立的运行环境,不会相互影响,毕竟有时你会遇到如使用 python2 和 python3的不同项目,共用一个运行环境可能无法同时适配。

    • 前提

      安装好python,并配置好环境变量。(可在命令窗口输入 python 指令查看)
    • 安装虚拟环境(virtualenv)
      • 使用python自带的 pip 包管理工具安装virtualenv
      • 进入命令窗口,输入 pip install virtualenv (若有多个python 版本,pip默认安装到python2, pip3安装到python3)
      • 命令窗口进入项目目录或者文件夹右键Git Bash 打开命令窗口(前提你有装Git),执行 virtualenv envname (envname指虚拟环境名,一般设为 venv 即可,当然你可以设置成其他名字)
      • 进入和退出虚拟环境(activate 和 deactivate)
        • 前提
          命令窗口进入项目所在目录,编辑器打开终端一般就是在项目的根目录了
        • 进入(执行命令)
          windows: ./venv(即envname)/Scripts/activate
          Linux: source ./venv/bin/activate
          虚拟环境进入成功,窗口路径前面会添加虚拟环境名,如:(venv)E:\admin_space\fast-api-example>
        • 退出(已进入虚拟环境)
          windows: deactivate
          Linux: deactivate
  • 安装FastAPI

    若使用虚拟环境,需提前进入虚拟环境后执行命令

    • pip install fastapi web框架
    • pip install uvicorn web服务器(flask用的是werkZeug),其实定义通信网关接口的工具集的库

    在Flask项目中,习惯用txt文件管理安装的第三方库和版本(requirements.txt)
    在根目录新建一个 requirements 的txt文件,(名字可随意),然后里面输入第三方库和版本
    如:

        fastapi==0.55.1   
        uvicorn==0.11.5
    

    其它扩展写法此处不涉及
    保存后 执行 pip install -r requirements.txt 安装

  • 试运行

    按照官方文档里例子 FastAPI
    新建一个 main.py 文件,按本人以前Flask项目习惯,我用runanpp.py(代替),意指整个程序的入口,即程序启动文件。

      ···
      # -*- coding: utf-8 -*-
      from fastapi import FastAPI
      
      app = FastAPI()
    
      @app.get("/")
      async def main():
          return {"message": "Hello World!"}
      
      # 启动服务1(类似java的main函数)
      if __name__ == '__main__':
          import uvicorn
          uvicorn.run(app, host="127.0.0.1", port=8000)    
          
      # 启动服务2,支持自动重启(类似java的main函数)
      if __name__ == '__main__':
          import uvicorn
          uvicorn.run(app="runapp:app", host="127.0.0.1", port=8000,reload=True)
      ···
    

    若我们文件中添加了启动服务的脚本代码,则我们直接运行该文件,服务会自动启动:
    即输入命令:python runapp.py (runapp.py 即 官方例子的 main.py)
    一般项目有个一个程序入口,我们在这里做一下初始配置。
    脚本扩展:
    通过上面的脚本启动服务,修改代码后不会自动重启,查看函数,跟命令行一样,支持各种配置(如:添加 reload=True 支持重新启动)
    注意:若要启用“重新加载”,即reload,应用程序必须作为字符串传入,即首个参数不能直接传入app,而是要参考命令行的写法,如 “app=runapp:app”,才能成功启动,不然会报错

    同样我们可以在命令行直接输入指令:uvicorn runapp:app --reload 启动程序
    注意:
    runapp,即文件名,不带文件后缀,看过一个讲解视频是带后缀,但我带后缀就报错,不能正常运行)
    app,即程序实例对象,即你FastAPI赋值的变量名
    –reload,即修改保存后,会自动重启

    这些都跟Flask很类似,注意文件所在的文件路径。

  • 模版引擎

    FatsAPI没有指定使用模版引擎,比较灵活,以前Flask用的Jinja2,后续也采用Jinja2来学习和实现网页

    安装Jinja2,又使用静态文件,把aiofiles也装上
    pin install jinja2
    pin install aiofiles
    通让的把这些库写到 requirements.txt文件中

    在项目中创建 templates 文件夹,把要创建的 html 模版文件都在放里面。
    Jinja2的语法这里涉及,这里主要举例子。

      ···
      from fastapi import FastAPI
      from starlette.requests import Request
      from starlette.templating import Jinja2Templates
    
      app = FastAPI()
      # 获取模版路径
      templates = Jinja2Templates(directory="./app/templates")
    
    
      @app.get("/")
      async def main():
          return {"message": "Hello World!"}
    
    
      @app.get("/homes")
      async def main(request: Request):
          return templates.TemplateResponse(
              'index.html',
              {'request': request, 'hello': 'hello Jinja2 12354'})   
    
      ···
    

    通过starlette引入 Request 和 Jinja2Templates
    函数中返回 templates.TemplateResponse(‘指定的模版文件’,Context),templates.TemplateResponse意思指返回 模版箱响应。
    注意:与Flask相比,函数必须返回 Request对象,并作为参数传到模版中,不然会访问失败,而Flask默认是this
    经过测试:
    Context必须是包含 request 键,并且对应值支持 get 取值的对象,不然会报:
    ValueError: context must include a “request” key 错误
    in TemplateResponse
    raise ValueError(‘context must include a “request” key’)

    前面提到函数返回request参数,并作为requst键的值是非必须的,作用等同于我们在Flask中使用模版时用的 this。

  • 试用表单提交数据

    表单提交数据,这里特指尝试POST提交方式。
    新建一个post数据的页面,简单定义为create.html,里面代码大致如下:

      ···
      <div>
          <form action="http://127.0.0.1:8000/users" method="post" enctype="application/x-www-form-urlencoded">
              <label>用户名:</label>
              <br>
              <input type="username" name="username">
              <br>
              <label>密码:</label>
              <br>
              <input type="password" name="password">
              <br>
              <input type="submit" value="提交">
              <br>
          </form>
      </div>
      ···
    

    action属性指定数据提交路径,可以用相对路径,这里我用了绝对路径。
    input中name属性的值,等同请求时的参数名。

    新建一个数据展示页面,简单定义为user.html,里面代码大致如下:

      ···
      <div>
          <div>
            <label>用户名:</label>
            <br>
            <span>{{ username }}</span>
            <br>
          </div>
          <div>
            <label>密码:</label>
            <br>
            <span>{{ password }}</span>
            <br>
          </div>
      </div>
      ···
    

    主要用于展示create.html表单中提交的内容。

    这里我们需要分别访问两个页面:

      ···
      # 用到Form(...),需要引入Form,同样在fastapi中
      from fastapi import FastAPI, Form
    
      # 访问表单页面
      @app.get("/create")
      async def create_user(request: Request):
          data = {'request': request}
          return templates.TemplateResponse('create.html', data)
      
      # 获取表单数据并展示(这里用post,与表单的method属性设置一致)
      @app.post("/users")
      async def user_info(request: Request, 
                          username: str = Form(...),
                          password: str = Form(...))
          data = {
              'request': request,
              'username': username,
              'password': password}
          return templates.TemplateResponse('user.html', data)
      ···
    

    注意:使用Form(…),还需要安装第三方库 python-multipart
    pip install python-multipart (方便管理,我们也写进requirements.txt中)

    Form(…) 的作用是:获取表单中对应的数据,函数中使用该方式获取参数,必须是post请求方式,get请求会报错。(其默认接收表单类型是:“application/x-www-form-urlencoded”)
    我们在Flask中获取表单数据(WerkZeug):request.form.get(‘参数名’, ‘’),而Form则是帮我们在传参时完成这些操作,提高开发效率,优化函数内部代码,专注于业务,而非获取参数。
    (注意:参数名需与表单input标签中的name属性的值一致)

    在Flask中,我们都是通过操作request对象来进行参数操作,FastAPI同样支持,使用的是starlette的Request和Response,这里不过多的阐述,因为我也没用过starlette
    简单:

    • get请求:
      request.query_params[‘参数名’] 或 request.query_params.get(‘参数名’, ‘’) (建议用get方式获取,避免参数不存在报错)
    • post请求:
      form = await request.form() (form()是一个异步操作,需要加await等待结果)
      form[‘参数名’] 或 form.get(‘参数名’, ‘’)
      好像稍微麻烦一点。。。。而且不能享受数据强制验证带来的便利(Pydantic)
  • 试用表单上传文件

    • 导入新模块

       ···
           # 接收列表类型需要
           from typing import List
           # 文件操作相关
           from fastapi import File, UplodFile
       ···
      
    • 创建表单文件

       ···
           <form action="/files" enctype="multipart/form-data" method="POST">
               <input type="file" name="files_list" multiple><br><br>
               <input type="file" name="files_name" multiple><br><br>
               <input type="submit" value="上传">
           </form>
       ···
      
    • 进入上传页面

       ···
           @app.get("/users")
           async def user_info(request: Request):
               data = {'request': request}
               return templates.TemplateResponse('user.html', data)
       ···
      
    • 获取数据并展示

       ···
           @app.post("/files")
           async def upload_files(request: Request,
                                  files_list: List[bytes] = File(...),
                                  files_name: List[UploadFile] = File(...)):
               data = {
                   'request': request,
                   'file_sizes': [len(file) for file in files_list],
                   'file_names': [file.filename for file in files_name]
               }
               return templates.TemplateResponse('user.html', data)
       ···
      

    我提交和展示都写在user.html页面了,浏览器跳转指定页面要用get请求。
    相较于提交普通的表单,上传文件用的是 File(…) 获取,作用类似Form(…),不深入阐释,因为也不是很懂。

    从typingm模块导入List的作用是为了接收列表类型的参数数据:

    • files_list: List[bytes] = File(…) (允许接收多个文件)
    • files_list: bytes = File(…) (只允许接收单个文件)

    其它一些文件操作,如获取文件名、类型等操作(文件类型必须是UploadFile,是starlette的):

    • files_name: List[UploadFile] = File(…)

    FatsAPI支持bytes和UploadFile两种文件格式,而UploadFile相较bytes的优点有:

    • 使用假脱机文件(超过内存文件存储限制,将存储在磁盘中)
    • 适用于大型文件,不会占用所有内存
    • 可以从上传的文件获取元数据
    • 具有类似文件的接口
  • 补充

    • Form(…) 和 File(…) 中‘…’ 代表什么
      理解为参数是必须的,为空会报错,Form(None)…则非必须
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值