FastApi SQLAlchemy SQLite

FastApi

fastapi是一个用于构建API 的现代、快速(高性能)的web框架,它是建立在Starlette和Pydantic基础上的。

Pydantic是一个基于Python类型提示来定义数据验证、序列化和文档的库,Starlette是一种轻量级的ASGI框架/工具包,适合用Python构建异步Web服务。FastAPI 依赖 Python 3.8 及更高版本。
在这里插入图片描述

开始案例

先安装fastapi 和 ASGI服务器

pip install fastapi
pip install uvicorn

然后写一个FastAPI

from typing import Union

import uvicorn
from fastapi import FastAPI

# 创建一个FastAPI应用实例
app = FastAPI()

# 定义一个带有动态参数的GET请求处理器,用于打招呼
@app.get("/hello/{name}")
async def say_hello(name: str):
    # 返回一个根据名字定制的打招呼消息
    return {"message": f"Hello {name}"}

# 定义另一个根路由GET请求处理器,功能与前一个根路由处理器不同
@app.get("/")
def read_root():
    # 返回一个简单的欢迎消息
    return {"Hello": "World"}

# 定义一个获取物品信息的GET请求处理器,接受一个物品ID和一个可选参数q
@app.get("/items/{item_id}")
def read_item(item_id: int, q: Union[str, None] = None):
    # 返回物品ID和可选参数q的信息
    return {"item_id": item_id, "q": q}

在命令行用uvicorn 运行

PS D:\Users\user\PycharmProjects\fastApiProject> uvicorn main:app --reload 
INFO:     Will watch for changes in these directories: ['D:\\Users\\user\\PycharmProjects\\fastApiProject']
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [30468] using WatchFiles
INFO:     Started server process [20408]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

也可以在python文件中直接运行

if __name__ == "__main__":
    uvicorn.run("main:app", host="127.0.0.1", port=8000,reload = True)

浏览器访问http://127.0.0.1:8000/ 可以看到输出了欢迎消息
在这里插入图片描述

访问http://127.0.0.1:8000/items/5?q=runoob 可以看到输出

在这里插入图片描述

FastAPI 交互式 API 文档

FastAPI 提供了内置的交互式 API 文档,使开发者能够轻松了解和测试 API 的各个端点。这个文档是自动生成的,基于 OpenAPI 规范,支持 Swagger UI 和 ReDoc 两种交互式界面。通过 FastAPI 的交互式 API 文档,开发者能够更轻松地理解和使用 API,提高开发效率。在运行 FastAPI 应用时,Uvicorn 同时启动了交互式 API 文档服务。

默认情况下,可以通过访问 http://127.0.0.1:8000/docs 来打开 Swagger UI 风格的文档:

在这里插入图片描述

Swagger UI 提供了一个直观的用户界面,用于浏览 API 的各个端点、查看请求和响应的结构,并支持直接在文档中进行 API 请求测试。通过 Swagger UI,你可以轻松理解每个路由操作的输入参数、输出格式和请求示例。

通过 http://127.0.0.1:8000/redoc 来打开 ReDoc 风格的文档。

在这里插入图片描述

ReDoc 是另一种交互式文档界面,具有清晰简洁的外观。它使得开发者能够以可读性强的方式查看 API 的描述、请求和响应。与 Swagger UI 不同,ReDoc 的设计强调文档的可视化和用户体验。

交互式文档的优势

  • 实时更新: 交互式文档会实时更新,反映出应用代码的最新更改。
  • 自动验证: 输入参数的类型和格式会得到自动验证,降低了错误的可能性。
  • 便于测试: 可以直接在文档中进行 API 请求测试,避免使用其他工具。

路径操作

FastAPI 支持多种常用的 HTTP 调用方式,包括:

  1. GET:用于获取资源,例如 @app.get("/items/{item_id}")
  2. POST:用于创建资源,例如 @app.post("/items/")
  3. PUT:用于更新资源,例如 @app.put("/items/{item_id}")
  4. DELETE:用于删除资源,例如 @app.delete("/items/{item_id}")
  5. PATCH:用于部分更新资源,例如 @app.patch("/items/{item_id}")

参数

路径操作装饰器的参数:

from typing import Union

import uvicorn
from fastapi import FastAPI

# 创建一个FastAPI应用实例
app = FastAPI()

# 定义一个post方法
@app.post("/items",tags=["这是items测试接口"],
          summary="这是items接口的 summary",
          description="这是items接口的description",
          response_description="这是items接口返回参数的description"
    )
def process_value(value: Union[int, float, str]) -> str:
    return f"Processed value: {value}"

if __name__ == "__main__":
    uvicorn.run("main:app", host="127.0.0.1", port=8000,reload = True)

在这里插入图片描述

include_router

include_router 用于将一个或多个路由器(APIRouter 实例)包含到主应用中。这使得你可以将路由组织成模块化的部分,方便管理和扩展。

比如目录结构如下的项目中

在这里插入图片描述

注意:main.py 与apps模块同级,都是在shopping下

appone.urls.py

from fastapi import APIRouter
app01 = APIRouter()

@app01.get("/food")
def get_food():
    return {"food": "pizza"}

@app01.get("/drink")
def get_drink():
    return {"drink": "water"}

apptwo.urls.py

from fastapi import APIRouter
app02 = APIRouter()

@app02.post("/login")
def user_login():
    return {"user": "login"}

@app02.post("/register")
def user_register():
    return {"user": "register"}

main.py

from typing import Union

import uvicorn
from fastapi import FastAPI
from apps.appone.urls import app01
from apps.apptwo.urls import app02

# 创建一个FastAPI应用实例
app = FastAPI()

# 将app01路由器包含进app路由器中,所有路径以"/shop"为前缀,这些路由将被标记为"商城中心接口"
app.include_router(app01, prefix="/shop",tags=["商城中心接口"])

# 将app02路由器包含进app路由器中,所有路径以"/user"为前缀,这些路由将被标记为"用户中心接口"
app.include_router(app02, prefix="/user",tags=["用户中心接口"])


if __name__ == "__main__":
    uvicorn.run("main:app", host="127.0.0.1", port=8000,reload = True)

查看API文档,可以看到分成了两个部分,商城中心接口以及用户中心接口

在这里插入图片描述

请求与响应

路径参数

可以在路径后用{}自定义参数传入函数内,路径上传入的参数都是作为str 字符串类型传入的,如果一定要传入某种类型,比如整型可以在函数参数内声明 类型def get_user(id:int) 声明后只能传入int类型的参数,如果类型错误会返回错误信息

@app01.get("/user/{id}")
def get_user(id:int):
    print(f"Getting user id:{id},type:{type(id)}")
    return {
        "user_id" : id,
        "name": "John Doe",
        "age": 30
    }

在这里插入图片描述

注意:路径匹配会根据代码从上到下匹配,如果有路径重名的情况,会执行在上面的函数,比如有路径/user/1/user/{id} 当id = 1 的时候,只会返回上面的信息

@app01.get("/user/1")
def get_user():
    return {
        "user_id" : "/user/1",
        "name": "John Doe",
        "age": 30

    }
@app01.get("/user/{id}")
def get_user(id:int):
    print(f"Getting user id:{id},type:{type(id)}")
    return {
        "user_id" : id,
        "name": "John Doe",
        "age": 30
    }

在这里插入图片描述

查询参数

可以在函数方法内加入查询参数,查询参数和路径参数可以混合使用,

@app02.get("/jobs/{kd}") # 路径参数
async def get_jobs(kd,gj,xl = "本科"): # 查询参数,没设置默认值就必须传入参数
    return {
        "kd":kd,
        "xl":xl,
        "gj":gj
    }

在这里插入图片描述

请求体数据

FastAPI 通过 Pydantic 来做类型强制检查(校验数据),不符合类型要求就会抛出异常。

from datetime import date
from typing import List, Optional, Union

from fastapi import APIRouter
from pydantic import BaseModel, Field, field_validator

app02 = APIRouter()

class Addr(BaseModel):
    province: str
    city: str

class User(BaseModel):
    # 定义User类,继承自BaseModel
    name:str = Field(title="用户名", description="用户名描述")
    # name属性表示用户的姓名,类型为字符串

    age:int = Field(default= 0,title="年龄",description="年龄描述",gt=0,lt=100) # gt:大于,lt:小于
    # age属性表示用户的年龄,是整型,默认值为0
    # 年龄的标题是"年龄",描述是"年龄描述"
    # 年龄必须大于0且小于100

    birth: Union[date, None] = None
    # birth属性表示用户的出生日期,类型为日期或者None
    # 默认值为None

    friends: List[int]
    # friends属性表示用户的朋友们的ID列表,类型为整型列表

    description: Optional[str] = None
    # description属性表示用户的描述,类型为可选的字符串
    # 默认值为None

    addr: Addr

    @field_validator("name")
    def name_must_be_alpha(cls, v):
        """
        确保名称字段只包含字母。
        此验证器确保传递给字段的值不包含任何非字母字符,
        以保持名称数据的整洁和一致性。
        参数:
            cls: 类本身, conventional usage in class methods.
            v: 待验证的名称字段值。
        返回:
            经验证只包含字母的字符串。
        异常:
            AssertionError: 如果字符串包含非字母字符。
        """
        # 检查变量v是否只包含字母
        assert v.isalpha(), "must only contain alphabetic characters"
        # 如果变量v通过检查,将其原样返回
        return v

class ResponseData(BaseModel):
    data: List[User]

@app02.post("/user")
async def get_user(user:User):
    print(type(user)) # <class 'apps.app02.User'>
    print(user.name, user.age, user.birth) # string 88 2024-08-29
    print(user.model_dump()) # {'name': 'string', 'age': 88, 'birth': datetime.date(2024, 8, 29), 'friends': [0], 'description': 'string', 'addr': {'province': 'string', 'city': 'string'}}
    return {
        "user":user
    }


@app02.post("/data")
async def get_data(data : ResponseData):
    return data

当我们编写了参数的数据限制之后,能够在接口文档中直观的查看到,以/data 接口为例

在这里插入图片描述

from表单数据

在 FastAPI 中,Form 模块用于处理表单数据的提交。它提供了一种便捷的方式来提取从 HTML 表单提交的数据。

具体来说,Form 主要用于处理 HTTP 请求中的表单数据。这些数据通常是通过 application/x-www-form-urlencodedmultipart/form-data 这样的内容类型提交的。以下是一些关键点:

  1. 处理表单数据Form 用于定义处理表单字段的模型。你可以在 FastAPI 路由中使用 Form 对象来提取表单字段的值。
  2. 与 Pydantic 结合使用:虽然 FastAPI 的核心数据模型使用 Pydantic 来进行数据验证,但表单数据的提取和验证通常通过 Form 来实现。
  3. 如何使用
    • 在视图函数中,你可以将 Form 对象作为参数,FastAPI 会自动解析请求中的表单数据并将其传递给视图函数。
    • Form 支持设置默认值、标记字段为必填项等功能。

主要用途

  • 处理用户输入的表单数据,例如在注册页面、登录页面等。
  • 提供简单的表单验证和处理机制。

首先 需要先使用pip install python-multipart 命令进行安装。

from datetime import date
from typing import List, Optional, Union

from fastapi import APIRouter,Form
from pydantic import BaseModel, Field, field_validator

app03 = APIRouter()

@app03.post("/regin")
async def get_user(username: str = Form(), password: str = Form()):
    print(f"username:{username},password:{password}")
    return {
        "username": username
    }

文件上传

文件上传主要包括UploadFilebytes 两种方式

首先介绍一下bytes方式上传文件

from typing import List

from fastapi import APIRouter,File

app04 = APIRouter()

@app04.post("/file")
async def get_file(file: bytes = File()):
    # 适合小文件上传
    print(file)
    return {
        "files": len(file)
    }

@app04.post("/files")
async def get_file(files: List[bytes] = File()):
    print(files)
    return {
        "files": len(files)
    }

在这里插入图片描述

UploadFile,先创建imgs 文件夹用于接收我们上传的文件

# 使用路径操作装饰器定义一个POST请求的端点"/uploadFile"
@app04.post("/uploadFile")
async def upload_file(file: UploadFile):
    """
    上传文件功能。

    - 参数:
        - file: 用户上传的文件,类型为UploadFile。

    - 返回:
        - 一个包含文件名的JSON响应。

    此函数接收上传的文件,打印文件信息,然后将文件保存到"imgs"文件夹下。
    """
    # 打印上传文件的信息
    print(file)

    # 拼接文件保存路径
    path = os.path.join("imgs", file.filename)

    # 以二进制写模式打开(或创建)目标文件
    with open(path, "wb") as f:
        # 遍历上传文件的每一行,写入到目标文件
        for line in file.file:
            f.write(line)

    # 返回上传文件的文件名
    return {
        "filename": file.filename
    }

@app04.post("/uploadFiles")
async def upload_file(files: List[UploadFile]):
    """
    上传文件功能。

    - 参数:
        - file: 用户上传的文件,类型为UploadFile。

    - 返回:
        - 一个包含文件名的JSON响应。

    此函数接收上传的文件,打印文件信息,然后将文件保存到"imgs"文件夹下。
    """
    # 打印上传文件的信息
    print(files)

    # 拼接文件保存路径
    for file in files:
        path = os.path.join("imgs", file.filename)

        # 以二进制写模式打开(或创建)目标文件
        with open(path, "wb") as f:
            # 遍历上传文件的每一行,写入到目标文件
            for line in file.file:
                f.write(line)
    # 返回上传文件的文件名
    return {
        "files": [file.filename for file in files]
    }

在这里插入图片描述

在这里插入图片描述

UploadFilebytes 在 FastAPI 中用于处理文件上传,但它们有显著的区别:

  1. UploadFile:
    • 功能:提供对上传文件的更高层次的抽象,包括文件的元数据(如文件名和 MIME 类型)和文件内容的异步读取。
    • 用法:适合处理大文件,因为它支持流式读取,不需要一次性将整个文件加载到内存中。
    • 示例await file.read() 读取文件内容。
  2. bytes:
    • 功能:直接处理文件的二进制内容。上传的文件内容会一次性加载到内存中,适合处理小文件。
    • 用法:更简单,但不适合大文件的上传和处理,因为内存消耗较大。
    • 示例files = List[bytes]

Request

# 创建一个API路由器实例,用于处理API请求
app05 = APIRouter()

# 定义一个处理POST请求的端点:/items
# 使用路径操作装饰器post,指定URL路径为"/items"
@app05.post("/items")
# 定义异步函数items,接收一个Request类型的参数request
async def items(request: Request):
    # 打印请求的URL
    print("URL", request.url)
    # 打印发起请求的客户端IP地址
    print("IP", request.client.host)
    # 打印请求的用户代理(User-Agent)
    print("agent", request.headers["user-agent"])
    # 打印请求携带的Cookies
    print("cookies",request.cookies)
    # 返回包含URL、IP、用户代理和Cookies信息的字典
    return {
        "url": request.url,
        "ip": request.client.host,
        "agent": request.headers["user-agent"],
        "cookies": request.cookies
    }

在这里插入图片描述

静态文件请求

# 将"/static"路径挂载到应用程序,用于提供静态文件服务
# 这里的StaticFiles是一个FastAPI框架中的类,它用于处理静态文件的HTTP请求
# 参数directory指定静态文件所在的目录,本例中为"statics"目录,指定后可以使用 /static/css/test.css访问静态文件
app.mount("/static",StaticFiles(directory="statics"))

在这里插入图片描述

响应模型参数

response_model 是 FastAPI 中一个重要的功能,用于定义 API 路由的响应数据模型。

# 定义用户输入模型,用于用户数据的接收
class UserIn(BaseModel):
    # 用户名,必填
    username: str
    # 密码,必填
    password: str
    # 邮箱,必填,使用EmailStr类型确保邮箱格式
    email: EmailStr
    # 完整姓名,可选
    full_name: Union[str, None] = None

# 定义用户输出模型,用于展示用户信息
class UserOut(BaseModel):
    # 用户名,必填
    username: str
    # 邮箱,必填,使用EmailStr类型确保邮箱格式
    email: EmailStr
    # 完整姓名,可选
    full_name: Union[str, None] = None

# 用户登录接口,接收UserIn类型数据,返回UserOut类型数据
@app06.post("/user/login", response_model=UserOut)
def create_user(user: UserIn):
    # 直接返回接收到的用户数据,实际项目中会进行复杂的认证逻辑
    return user

response_model 是 FastAPI 中的一个参数,专用于指定 API 响应的模型。除了基本的 response_model 之外,FastAPI 还提供了一些其他参数来控制响应的行为,具体包括:

  1. response_model_exclude_unset
  • 作用:如果设置为 True,仅在响应中包括模型中显式设置的字段,而不包括默认值的字段。
  • 用法:适用于只希望返回用户设置过的字段,而不返回默认值的场景。
@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: int):
    return {"name": "Item Name", "price": 10.5}
  1. response_model_exclude_defaults
  • 作用:如果设置为 True,响应中将排除具有默认值的字段。
  • 用法:用于只返回已修改的字段,而忽略那些未被修改的默认字段。
@app.get("/items/{item_id}", response_model=Item, response_model_exclude_defaults=True)
async def read_item(item_id: int):
    return {"name": "Item Name", "price": 10.5}
  1. response_model_exclude
  • 作用:指定一个字段名列表,这些字段将被从响应中排除。
  • 用法:用于排除某些字段的响应数据,允许更精细的控制。
@app.get("/items/{item_id}", response_model=Item, response_model_exclude={"tax"})
async def read_item(item_id: int):
    return {"name": "Item Name", "description": "Item Description", "price": 10.5, "tax": 1.5}
  1. response_model_include
  • 作用:指定一个字段名列表,仅包括这些字段在响应中。
  • 用法:用于只返回特定的字段,而忽略其他字段。
@app.get("/items/{item_id}", response_model=Item, response_model_include={"name", "price"})
async def read_item(item_id: int):
    return {"name": "Item Name", "description": "Item Description", "price": 10.5, "tax": 1.5}

这些参数使得 response_model 更加灵活,允许开发者根据需要定制响应的内容和格式。

asyncawait 简介

在 FastAPI 中,asyncawait 用于处理异步操作,以提高应用程序的性能和响应速度。了解它们的区别可以帮助你更有效地使用 FastAPI 来构建高性能的应用程序。

  • async def: 这是定义一个异步函数的关键字。异步函数(也称为协程)允许你在函数内部使用 await 关键字来等待其他协程完成。它们在 I/O 密集型任务中尤其有用,如处理网络请求或数据库操作。
  • await: 这是用于暂停协程的执行,直到另一个协程完成。这使得协程可以在等待期间释放控制权,从而允许其他协程继续运行。await 只能在异步函数内部使用。
同步 vs 异步
  1. 同步方法 (def 方法):

    • 阻塞: 在处理某些操作时,当前请求会被阻塞,直到操作完成。
    • 简单: 代码结构简单,但在处理大量并发请求时可能会导致性能瓶颈。
    @app.get("/sync-endpoint")
    def sync_endpoint():
        result = some_blocking_io_operation()
        return {"result": result}
    
  2. 异步方法 (async def 方法):

    • 非阻塞: 使用 await 等待 I/O 操作,而不会阻塞整个请求处理过程。这样可以同时处理更多的请求,提高应用程序的吞吐量。
    • 复杂: 代码结构稍微复杂一些,需要注意异步操作和异常处理。
    @app.get("/async-endpoint")
    async def async_endpoint():
        result = await some_non_blocking_io_operation()
        return {"result": result}
    

异步的优点

  • 高性能: 异步处理允许应用程序在等待 I/O 操作时继续处理其他任务,从而提高整体性能。
  • 更好地处理高并发: 在高并发场景下,异步方法可以更有效地管理资源,提高响应速度。

何时使用异步

  • I/O 密集型操作: 当你的应用程序涉及到大量的网络请求、文件操作或数据库访问时,使用异步方法可以显著提高性能。
  • 高并发: 如果你的应用程序需要处理大量并发请求,异步编程可以帮助你更好地利用系统资源。

jinja2模板

Jinja2 是一个用于 Python 的模板引擎,它的作用是帮助生成动态 HTML 内容。它允许将逻辑从代码中分离出来,将数据嵌入到 HTML 模板中,从而创建动态网页。

1. 变量输出

功能说明: 变量输出是 Jinja2 的基础功能之一,它允许你在模板中插入并显示动态数据。通过 {{ ... }} 语法,你可以直接引用传递给模板的变量,并将其渲染为 HTML。这使得模板能够动态展示数据内容,而不是硬编码静态文本。

示例:

<p>Hello, {{ user.name }}!</p>

在这个示例中,{{ user.name }} 语法用于插入 user 对象的 name 属性值。当模板被渲染时,这个表达式会被替换成实际的 name 值,例如 "Alice",最终输出 <p>Hello, Alice!</p>

2. 控制结构

功能说明: Jinja2 提供了强大的控制结构功能,使得模板能够执行逻辑判断和重复操作。通过 {% ... %} 语法,你可以实现条件判断(if 语句)和循环遍历(for 语句)。这些功能允许你根据不同条件动态地生成 HTML 内容或对数据集合进行迭代处理。

  • 条件语句{% if ... %} 语法允许根据变量的值执行不同的代码块。例如,可以根据用户是否登录来显示不同的内容。
  • 循环语句{% for ... %} 语法用于遍历列表或字典中的每一个元素,可以生成一组重复的 HTML 元素,如列表项或表格行。

示例:

条件语句:

{% if user.is_authenticated %}
  <p>Welcome, {{ user.name }}!</p>
{% else %}
  <p>Please log in.</p>
{% endif %}

如果 user.is_authenticatedTrue,模板会显示欢迎信息;否则,会提示用户登录。

循环语句:

<ul>
{% for item in items %}
  <li>{{ item }}</li>
{% else %}
  <li>No items found.</li>
{% endfor %}
</ul>

这个示例遍历 items 列表并生成每个项的列表项。如果列表为空,则显示 “No items found” 的提示。

3. 过滤器

功能说明: 过滤器允许你在渲染模板时对变量进行处理和格式化。通过 | 符号应用过滤器,可以在输出数据之前对其进行转换,例如改变文本的大小写、格式化日期等。过滤器可以简化模板中的数据处理过程,使得模板更简洁、逻辑更清晰。

示例:

基本用法:

<p>{{ name|capitalize }}</p>

{{ name|capitalize }} 会将 name 的值转换为首字母大写,例如 "john" 变成 "John"

其他常用过滤器:

<p>{{ name|lower }}</p>   <!-- 将文本转换为小写 -->
<p>{{ name|upper }}</p>   <!-- 将文本转换为大写 -->
<p>{{ list|length }}</p>  <!-- 获取列表的长度 -->

这些过滤器用于对输出数据进行常见的转换和计算。

4.

功能说明: 宏是 Jinja2 提供的一种机制,用于创建可重用的模板片段。类似于编程中的函数,宏可以封装模板代码,使其在多个地方复用,从而避免代码重复。宏可以接收参数,并在调用时根据参数生成不同的内容。

示例:

定义宏:

{% macro input(name, value='', type='text') %}
  <input type="{{ type }}" name="{{ name }}" value="{{ value }}">
{% endmacro %}

这个宏 input 定义了一个 HTML 输入框,并允许通过参数设置输入框的 namevaluetype 属性。

使用宏:

{{ input('username') }}

在模板中调用宏 input('username') 会生成一个 <input> 元素,name 属性为 username,其他属性使用宏的默认值。

5. 模板继承

功能说明: 模板继承是一种强大的机制,允许你创建一个基础模板(父模板),并在子模板中扩展或重写父模板的内容。通过定义块(block)区域,父模板可以提供一个结构化的框架,而子模板则可以在特定区域插入或替换内容。这种方式促进了模板代码的重用和结构的组织。

示例:

父模板:

<!DOCTYPE html>
<html>
<head>
  <title>{% block title %}Default Title{% endblock %}</title>
</head>
<body>
  <header>
    <h1>{% block header %}Header{% endblock %}</h1>
  </header>
  <main>
    {% block content %}Default content{% endblock %}
  </main>
</body>
</html>

在父模板中定义了 titleheadercontent 三个块,这些块可以在子模板中被重写。

子模板:

{% extends "base.html" %}

{% block title %}My Page Title{% endblock %}

{% block content %}
  <p>This is the content of my page.</p>
{% endblock %}

子模板继承了 base.html 的结构,并重写了 titlecontent 块的内容,从而定制化页面内容。

6. 注释

功能说明: 注释功能允许在模板中添加注释文本,这些文本不会出现在最终的渲染结果中。注释用于解释代码的意图,提供额外的信息或提醒,帮助维护和理解模板代码。

示例:

{# This is a comment #}

注释在模板中以 {# ... #} 语法包围,这些注释会在渲染过程中被忽略,不会出现在生成的 HTML 中。

7. 测试和逻辑

功能说明: Jinja2 提供了测试和逻辑功能,使得模板可以进行复杂的数据验证和条件判断。你可以使用 is 运算符测试变量的类型或存在性,使用逻辑表达式执行更复杂的判断。这种功能使得模板能够动态处理数据,并根据不同情况生成相应的内容。

示例:

测试变量:

{% if user is defined %}
  <p>User is defined.</p>
{% endif %}

{% if user is defined %} 语法检查 user 变量是否被定义,如果是,则显示相关内容。

逻辑表达式:

{% if user.age > 18 %}
  <p>Adult</p>
{% else %}
  <p>Not an adult</p>
{% endif %}

这个例子使用逻辑表达式检查 user.age 是否大于 18,根据结果显示不同的内容。

案例:

main.py

import uvicorn
from fastapi import FastAPI,Request
from fastapi.templating import  Jinja2Templates

# 创建一个FastAPI应用实例
app = FastAPI()

templates = Jinja2Templates(directory="templates")

@app.get("/index")
def index(request:Request):
    name = "root"
    age = 18
    books = ["python", "java", "c++"]
    infos = {
        "name": "root",
        "age": 18,
        "addr": "北京"
    }
    return templates.TemplateResponse(
        "index.html",
        {
            "request": request,
            "user": name,
            "age": age,
            "books": books,
            "infos": infos
        },
    )

if __name__ == "__main__":
    uvicorn.run("main:app", host="127.0.0.1", port=8888,reload = True)

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<p> 用户名:{{ user }}</p>
<p> 年龄:{{ age }}</p>
 <ul>
        {% for book in books %}
        <li>{{ book }}</li>
        {% endfor %}
 </ul>
</body>
</html>

目录结构

在这里插入图片描述

输出:
在这里插入图片描述

ORM操作

ORM操作以SQLLite为例

SQLite 是一个开源的关系型数据库管理系统(RDBMS),具有以下几个显著特点:

  1. 轻量级和嵌入式
  • 单文件存储:SQLite 的数据库以单一的文件形式存储所有数据,包括表、索引和事务日志。这使得 SQLite 易于部署和管理。
  • 无服务器架构:SQLite 不需要一个独立的服务器进程来运行。它直接与应用程序进程一起运行,适合嵌入到应用程序中。
  1. 自包含
  • 独立性:SQLite 不依赖于外部库或服务。它包括了完整的数据库引擎和所需的功能,所有的代码和数据都在一个文件中。
  1. SQL 支持
  • 标准 SQL:SQLite 支持大部分标准 SQL 语法,包括数据定义语言(DDL)、数据操作语言(DML)和数据控制语言(DCL)。
  • 事务支持:SQLite 支持 ACID(原子性、一致性、隔离性和持久性)事务,以确保数据的完整性。
    • ‌**原子性(Atomicity)**‌:确保事务内的操作要么全部完成,要么全部不完成,不会出现部分完成的情况。
    • ‌**一致性(Consistency)**‌:确保数据库从一个一致的状态转变到另一个一致的状态。
    • ‌**隔离性(Isolation)**‌:允许多个并发事务同时进行,而不会相互干扰。
    • ‌**持久性(Durability)**‌:一旦事务提交,其对数据库的更改就是永久的,即使系统崩溃也不会丢失。
  1. 跨平台
  • 多平台支持:SQLite 支持多种操作系统,包括 Windows、macOS、Linux、iOS 和 Android。这使得它在不同环境中具有很好的兼容性。
  1. 性能
  • 高效性:SQLite 设计为高效的读取性能和适度的写入性能,尤其适合轻量级或中等规模的应用程序。
  1. 零配置
  • 无需配置:SQLite 不需要进行复杂的配置或管理。你只需将 SQLite 数据库文件放在适当的位置,就可以开始使用。
  1. 扩展性
  • 扩展功能:SQLite 允许通过加载动态链接库(DLL)来扩展功能,包括自定义函数、虚拟表等。
  1. 广泛应用
  • 使用场景:SQLite 被广泛应用于移动应用(如 iOS 和 Android)、桌面软件、嵌入式设备(如路由器、家电)以及浏览器(如 Firefox 和 Chrome)等各种场景。
  1. 社区和支持
  • 开源项目:SQLite 是一个开源项目,代码和文档可以自由获取。社区活跃,提供广泛的支持和资源。
  1. 事务日志
  • WAL 和 DELETE 模式:SQLite 提供两种事务日志模式,WAL(Write-Ahead Logging)和 DELETE,这两种模式具有不同的性能和存储特性。

SQLite 的设计理念是提供一个轻便、快速、可靠的数据库解决方案,非常适合需要在本地或嵌入式环境中存储和管理数据的应用。

1. 使用 SQLAlchemy

SQLAlchemy 是一个功能强大的数据库工具包和 ORM 库,支持同步和异步操作。

在这里插入图片描述

示例:FastAPI 与 SQLAlchemy 的集成

这是一个结合 FastAPI 和 SQLAlchemy 进行数据库操作的简单示例:

  1. 定义模型:

    from sqlalchemy import create_engine, Column, Integer, String
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy.orm import sessionmaker
    
    DATABASE_URL = "sqlite:///./test.db"
    engine = create_engine(DATABASE_URL, echo=True)
    SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
    Base = declarative_base()
    
    class Item(Base):
        __tablename__ = 'items'
        id = Column(Integer, primary_key=True, index=True)
        name = Column(String, index=True)
    
  2. 创建 FastAPI 应用和路由:

    from fastapi import FastAPI, Depends
    from sqlalchemy.orm import Session
    from sqlalchemy.future import select
    
    app = FastAPI()
    
    def get_db():
        db = SessionLocal()
        try:
            yield db
        finally:
            db.close()
    
    @app.get("/items/{item_id}")
    async def read_item(item_id: int, db: Session = Depends(get_db)):
        result = await db.execute(select(Item).filter(Item.id == item_id))
        item = result.scalar_one_or_none()
        return item
    

SQLAlchemy 提供了两种主要的接口来与数据库交互:ORM(对象关系映射)Core(核心)。它们各自有不同的使用场景和特点。

SQLAlchemy 的ORM与Core

ORM(对象关系映射)

特点

  • 对象与数据库表的映射: ORM 通过将 Python 对象映射到数据库表,使得数据库操作可以通过对象方法和属性来完成。
  • 高级抽象: 提供了更高层次的抽象,简化了数据库操作。

示例

from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

Base = declarative_base()

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(String)
    age = Column(Integer)

# 设置数据库连接
engine = create_engine('sqlite:///example.db')
Base.metadata.create_all(engine)

Session = sessionmaker(bind=engine)
session = Session()

# 创建一个新的用户
new_user = User(name='Alice', age=30)
session.add(new_user)
session.commit()

优缺点

  • 优点:
    • 通过对象操作简化了数据库操作。
    • 自动处理复杂的关联关系和查询。
  • 缺点:
    • 性能开销相对较高,特别是在处理复杂查询时。
    • 可能对数据库结构变化不够灵活。
Core(核心)

特点

  • 更接近 SQL: Core 提供了对 SQL 的更直接控制,使用 SQL 表达式语言构建查询。
  • 更灵活: 允许开发者在更底层控制 SQL 生成和执行。

示例

from sqlalchemy import create_engine, Table, Column, Integer, String, MetaData

engine = create_engine('sqlite:///example.db')
metadata = MetaData()

users = Table('users', metadata,
    Column('id', Integer, primary_key=True),
    Column('name', String),
    Column('age', Integer)
)

metadata.create_all(engine)

# 插入数据
with engine.connect() as conn:
    conn.execute(users.insert().values(name='Bob', age=25))

优缺点

  • 优点:
    • 提供了对 SQL 查询的更细粒度控制。
    • 性能可能更好,特别是在执行复杂查询时。
  • 缺点:
    • 需要手动管理 SQL 和表结构。
    • 可能需要编写更多的代码来实现相同的功能。
总结
  • ORM 适合需要与数据库交互的对象导向应用,提供了更高层次的抽象和简化的操作。
  • Core 适合需要精确控制 SQL 查询或执行复杂数据库操作的场景,提供了更直接的 SQL 接口和更好的性能。

中间件与CORS

在 FastAPI 中,中间件(middleware)是一个处理请求和响应过程的组件,它位于请求到达路由处理函数和响应返回客户端之间。中间件允许你在处理请求之前和处理响应之后执行一些通用的操作。它们可以用来处理各种任务,比如请求日志、请求修改、响应修改、错误处理、跨域资源共享(CORS)设置等。

在这里插入图片描述

中间件的用途

  1. 请求和响应处理
    • 中间件可以在请求到达路由处理函数之前进行预处理,比如验证请求头或添加日志。
    • 它们也可以在响应发送给客户端之前进行处理,比如修改响应内容或添加自定义的响应头。
  2. 错误处理
    • 捕捉和处理应用程序中的异常,生成统一的错误响应格式。
  3. 身份验证和授权
    • 在请求到达路由之前,进行身份验证和授权检查,确保用户有权访问请求的资源。
  4. 日志记录
    • 记录每个请求的详细信息,比如请求路径、方法、响应时间等,以便于后续分析和调试。
  5. 跨域资源共享(CORS)
    • 配置允许哪些来源可以访问你的 API,通过添加适当的 CORS 头部来控制跨域请求。
  6. 请求和响应转换
    • 在请求到达路由处理函数之前或在响应发送之前,转换请求体或响应体的格式。

在 FastAPI 中使用中间件

FastAPI 提供了一种简单的方法来添加中间件。你可以使用 Starlette 库中的中间件类,因为 FastAPI 是构建在 Starlette 之上的。以下是如何在 FastAPI 中使用中间件的一个示例:

示例:中间件

比如有两个中间件,会在访问路由处理函数前访问。中间件执行顺序是:m1 -> m2 -> 路由处理函数,(发起请求时访问的中间件的顺序是越在代码文件下方的中间件越先被访问)

INFO:     127.0.0.1:53571 - "GET /docs HTTP/1.1" 200 OK
m1 request
m2 request
m2 response
m1 response
import uvicorn

from fastapi import FastAPI, Request, Response
import time

app = FastAPI()
# 中间件执行顺序:m1 -> m2 -> 路由处理函数

# 定义一个HTTP请求的中间件m2
@app.middleware("http")
async def m2(request: Request, call_next):
    # 处理请求前打印标识信息
    print("m2 request")
    # 调用下一个中间件或最终的应用处理器/控制器
    response = await call_next(request)
    # 处理响应前修改响应头,添加作者信息
    response.headers["author"] = "hzp"
    # 处理响应前打印标识信息
    print("m2 response")
    # 返回响应
    return response

# 定义一个HTTP请求的中间件m1
@app.middleware("http")
async def m1(request: Request, call_next):
    # 处理请求前打印标识信息
    print("m1 request")
    # # 检查请求客户端的主机是否在黑名单中
    # if request.client.host in ["127.0.0.1"]:
    #     # 如果客户端主机在黑名单中,返回403禁止访问响应
    #     return Response(status_code=403,content="Blacklist!")
    # 检查请求的URL路径是否为特定值
    # if request.url.path in ["/user"]:
    #     # 如果路径匹配,则返回一个包含特定内容和状态码的响应
    #     return Response(status_code=403, content="/user forbidden!")
    # 调用下一个中间件或最终的应用处理器/控制器
    # 记录请求开始时间
    start = time.time()

    # 调用下一个请求处理函数,等待其执行结果
    # 此处演示了异步调用,以提高程序的执行效率
    response = await call_next(request)

    # 记录请求结束时间,以便后续计算请求处理时间
    end = time.time()

    response.headers["ProcessTimer"] = str(end - start)
    # 处理响应前打印标识信息
    print("m1 response")
    # 返回响应
    return response

@app.get("/hello")
async def read_root():
    time.sleep(2) # 模拟请求处理时间,睡眠两秒钟
    return {"Hello": "World"}


if __name__ == "__main__":
    uvicorn.run("main:app", host="127.0.0.1", port=8898, reload=True)
示例:CORS 中间件

跨域请求指的是在一个网站(或应用)中,向另一个不同域名、协议或端口的服务器发出的网络请求。由于浏览器的安全策略,通常会限制这种请求,防止潜在的恶意行为。这种安全机制叫做“同源策略”。跨域请求需要服务器设置特定的头部,如 Access-Control-Allow-Origin,来允许来自其他域的请求访问其资源。

FastAPI 内置了 CORS 中间件,使用起来也非常简单:

from fastapi import FastAPI
from starlette.middleware.cors import CORSMiddleware

app = FastAPI()

# 添加 CORS 中间件
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 允许所有来源
    allow_credentials=True,
    allow_methods=["*"],  # 允许所有方法
    allow_headers=["*"],  # 允许所有头部
)

@app.get("/")
async def read_root():
    return {"Hello": "World"}
return Response(status_code=403, content="/user forbidden!")
# 调用下一个中间件或最终的应用处理器/控制器
# 记录请求开始时间
start = time.time()

# 调用下一个请求处理函数,等待其执行结果
# 此处演示了异步调用,以提高程序的执行效率
response = await call_next(request)

# 记录请求结束时间,以便后续计算请求处理时间
end = time.time()

response.headers["ProcessTimer"] = str(end - start)
# 处理响应前打印标识信息
print("m1 response")
# 返回响应
return response

@app.get(“/hello”)
async def read_root():
time.sleep(2) # 模拟请求处理时间,睡眠两秒钟
return {“Hello”: “World”}

if name == “main”:
uvicorn.run(“main:app”, host=“127.0.0.1”, port=8898, reload=True)




#### 示例:CORS 中间件

跨域请求指的是在一个网站(或应用)中,向另一个不同域名、协议或端口的服务器发出的网络请求。由于浏览器的安全策略,通常会限制这种请求,防止潜在的恶意行为。这种安全机制叫做“同源策略”。跨域请求需要服务器设置特定的头部,如 `Access-Control-Allow-Origin`,来允许来自其他域的请求访问其资源。

FastAPI 内置了 CORS 中间件,使用起来也非常简单:

```python
from fastapi import FastAPI
from starlette.middleware.cors import CORSMiddleware

app = FastAPI()

# 添加 CORS 中间件
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 允许所有来源
    allow_credentials=True,
    allow_methods=["*"],  # 允许所有方法
    allow_headers=["*"],  # 允许所有头部
)

@app.get("/")
async def read_root():
    return {"Hello": "World"}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Qt编写的modbus模拟器/支持网络和串口以及websocket/支持网络rtu

一、使用说明 1.1 设备模拟-Com 第一步&#xff0c;填写要模拟的设备地址&#xff0c;0表示自动处理&#xff0c;也就是收到什么地址就应答什么地址。第二步&#xff0c;填写对应的串口号和波特率。第三步&#xff0c;单击打开串口&#xff0c;成功后会变成关闭串口字样。单击…

智慧公厕厂家:智慧公厕建设推动城市公厕智能化变革

随着科技的不断进步&#xff0c;智慧公厕厂家正以创新之力推动着城市公厕的智能化变革。 一、提升用户体验 智慧公厕为使用者带来了前所未有的便利。通过实时显示厕位使用情况&#xff0c;避免了旅客的无效排队&#xff0c;节省了时间。感应式设备如水龙头、洗手液等&#xff…

工业数据采集网关如何与设备进行连接?天拓四方

在工业自动化与智能化日益普及的今天&#xff0c;工业数据采集网关成为了连接各种工业设备与数据中心的桥梁。 一、工业数据采集网关的作用 工业数据采集网关&#xff0c;作为工业自动化系统的核心组成部分&#xff0c;负责实时采集、处理和传输来自各种工业设备的数据。它能…

RS232和RS485

文章目录 RS232和RS485编程与UART一摸一样RS232RS485 前情提要&#xff1a;UART的缺点 电气接口不统一 UART只是对信号的时序进行了定义&#xff0c;而未定义接口的电气特性 电压电平不兼容 UART通信中通常使用处理器的电平&#xff08;如TTL电平&#xff09;&#xff0c;但不…

【Vue】Vue3.0(十三)中标签属性ref(加在普通标签上、加在组件标签上)、局部样式

上篇文章&#xff1a; 【Vue】Vue3.0 &#xff08;十二&#xff09;、watchEffect 和watch的区别及使用 &#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;Vue专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年10月18日20点56分 文章目录 基本…

主键 外键

主键 外键 在关系型数据库中&#xff0c;主键&#xff08;Primary Key&#xff09;和外键&#xff08;Foreign Key&#xff09;是用于维护数据完整性和建立表之间关系的重要概念。 主键&#xff08;Primary Key&#xff09; 定义: 主键是一个或多个列的组合&#xff0c;其值能…

初始Python篇(4)—— 元组、字典

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a; Python 目录 元组 相关概念 元组的创建与删除 元组的遍历 元组生成式 字典 相关概念 字典的创建与删除 字典的遍历与访问 字典…

Maple :一款强大的计算软件,广泛应用于数学、工程、物理和其他科学领域

Maple 是一款强大的计算软件&#xff0c;广泛应用于数学、工程、物理和其他科学领域。它以其符号计算、数值计算和图形可视化能力而闻名&#xff0c;适用于从基础到高级的数学问题。以下是对 Maple 的详细介绍&#xff1a; 1. 基本功能 符号计算 &#xff1a;Maple 能够处理复…

RBAC 模型

系统权限控制最常采用的访问控制模型就是 RBAC 模型 。 什么是 RBAC 呢&#xff1f; RBAC 即基于角色的权限访问控制&#xff08;Role-Based Access Control&#xff09;。这是一种通过角色关联权限&#xff0c;角色同时又关联用户的授权的方式。 简单地说&#xff1a;一个用…

鸿蒙网络编程系列7-TLS安全数据传输单向认证示例

1.TLS简介 TLS&#xff08;Transport Layer Security&#xff09;协议的前身是SSL&#xff08;Secure Socket Layer&#xff09;安全套接层协议&#xff0c;由Netscape公司于1994年提出&#xff0c;是一套网络通信安全协议。IETF&#xff08;The Internet Engineering Task Fo…

ORACLE 19C安装 RAC报错

1. 问题描述 在Oracle 19C RAC的安装过程中&#xff0c;使用克隆方式在两个节点上部署集群。当第一个节点配置好基础服务后&#xff0c;关机并克隆节点。当尝试在第二个节点上通过页面进行RAC安装时&#xff0c;出现以下错误&#xff1a; [INS-32070] Could not remove the n…

Maven--简略

简介 Apache旗下的一款开源项目&#xff0c;用来进行项目构建&#xff0c;帮助开发者管理项目中的jar及jar包之间的依赖&#xff0c;还拥有项目编译、测试、打包的功能。 管理方式 统一建立一个jar仓库&#xff0c;把jar上传至统一的仓库&#xff0c;使用时&#xff0c;配置…

ArcGIS无插件加载(无偏移)在线天地图高清影像与街道地图指南

在地理信息系统&#xff08;GIS&#xff09;的应用中&#xff0c;加载高清影像与街道地图对于地图制图、影像查阅、空间数据分析等工作至关重要。天地图作为官方出品的地图服务&#xff0c;以其标准的数据、较快的影像更新速度等特点受到广泛欢迎。以下是如何在ArcGIS中无插件加…

【论文速读】Prompt Tuning:The Power of Scale for Parameter-Effificient Prompt Tuning

arxiv&#xff1a;2104.08691v2 摘要 在这项工作中&#xff0c;我们探索了“prompt tuning&#xff08;提示调优&#xff09;”&#xff0c;这是一种简单而有效的机制&#xff0c;用于学习“soft prompts&#xff08;软提示&#xff09;”&#xff0c;以条件下冻结的语言模型…

MATLAB智能算法 - AntColonyOptimization蚁群算法

AntColonyOptimization蚁群算法 智能算法是路线规划、深度学习等等一系列领域所使用的优化算法&#xff0c;是算法进阶之路的必备之路。 前言&#xff1a;本文主要围绕解决TSP旅行商问题展开&#xff0c;对于机器人的路线规划以及非线性方程求解的问题等解决方案 对于一些其他优…

leetcode289:生命游戏

根据 百度百科 &#xff0c; 生命游戏 &#xff0c;简称为 生命 &#xff0c;是英国数学家约翰何顿康威在 1970 年发明的细胞自动机。 给定一个包含 m n 个格子的面板&#xff0c;每一个格子都可以看成是一个细胞。每个细胞都具有一个初始状态&#xff1a; 1 即为 活细胞 &am…

Nest.js 实战 (十四):如何获取客户端真实 IP

问题解析 在 Nest.js 应用中&#xff0c;当你试图通过 request.ip 获取客户端的 IP 地址时&#xff0c;如果总是返回 ::1 或者 ::ffff:127.0.0.1&#xff0c;这通常意味着请求来自本地主机。 因为在前后端分离应用中&#xff0c;前端请求后端服务一般的做法都是通过代理&…

springboot051医院管理系统(论文+源码)_kaic

医院管理系统 摘要 随着信息互联网信息的飞速发展&#xff0c;医院也在创建着属于自己的管理系统。本文介绍了医院管理系统的开发全过程。通过分析企业对于医院管理系统的需求&#xff0c;创建了一个计算机管理医院管理系统的方案。文章介绍了医院管理系统的系统分析部分&#…

R语言机器学习遥感数据处理与模型空间预测技术及实际项目案例分析

随机森林作为一种集成学习方法&#xff0c;在处理复杂数据分析任务中特别是遥感数据分析中表现出色。通过构建大量的决策树并引入随机性&#xff0c;随机森林在降低模型方差和过拟合风险方面具有显著优势。在训练过程中&#xff0c;使用Bootstrap抽样生成不同的训练集&#xff…