欢迎光临
我们一直在努力

Python 虚拟环境 virtualenv & uvicorn 服务搭建 & FAstAPI 使用

虚拟环境

为什么需要虚拟环境?

Python项目的一大痛点是依赖管理——项目A需要fastapi==0.95,项目B需要fastapi==0.100,若全部装到系统Python中必然冲突。虚拟环境(Virtual Environment)正是为解决此问题而生:它为每个项目创建独立的Python运行环境,实现依赖隔离。

虚拟环境工具选型

工具名称类型Python版本支持安装方式特点适用场景
venv(推荐) 内置模块 ≥ 3.3 无需安装,内置 轻量级、官方推荐、使用简单 通用开发、日常项目
virtualenv 第三方工具 2.x 和 3.x pip install virtualenv 功能丰富、兼容多版本 需要兼容旧版本或高级功能
conda Anaconda自带 2.x 和 3.x 随 Anaconda/Miniconda 安装 跨语言包管理、数据科学生态 数据科学、机器学习项目

若需更老版本支持,可使用 virtualenv(Python 2兼容)。下面使用virtualenv来做示例。

虚拟环境创建

安装工具

pip install virtualenv

Collecting virtualenv   Using cached virtualenv-21.5.1-py3-none-any.whl.metadata (3.4 kB) Collecting distlib<1,>=0.3.7 (from virtualenv)   Using cached distlib-0.4.3-py2.py3-none-any.whl.metadata (5.3 kB) Collecting filelock<4,>=3.24.2 (from virtualenv)   Using cached filelock-3.29.5-py3-none-any.whl.metadata (2.0 kB) Collecting platformdirs<5,>=3.9.1 (from virtualenv)   Using cached platformdirs-4.10.0-py3-none-any.whl.metadata (5.5 kB) Collecting python-discovery>=1.4.2 (from virtualenv)   Using cached python_discovery-1.4.3-py3-none-any.whl.metadata (5.6 kB) Using cached virtualenv-21.5.1-py3-none-any.whl (4.6 MB) Using cached distlib-0.4.3-py2.py3-none-any.whl (470 kB) Using cached filelock-3.29.5-py3-none-any.whl (45 kB) Using cached platformdirs-4.10.0-py3-none-any.whl (22 kB) Using cached python_discovery-1.4.3-py3-none-any.whl (33 kB) Installing collected packages: distlib, platformdirs, filelock, python-discovery, virtualenv Successfully installed distlib-0.4.3 filelock-3.29.5 platformdirs-4.10.0 python-discovery-1.4.3 virtualenv-21.5.1

创建虚拟环境

python -m virtualenv .venv

标准用法:virtualenv .venv

.venv 是虚拟环境目录

创建后目录:

.venv/ ├── bin/            # 在 Unix/Linux 系统上 │   ├── activate    # 激活脚本 │   ├── python      # 环境 Python 解释器 │   └── pip         # 环境的 pip ├── Scripts/        # 在 Windows 系统上 │   ├── activate    # 激活脚本 │   ├── python.exe  # 环境 Python 解释器 │   └── pip.exe     # 环境的 pip └── Lib/            # 安装的第三方库

启用虚拟环境

Windows(CMD / PowerShell):

.\\.venv\\Scripts\\activate

包操作

查看命令:pip list 

安装:pip install fastapi

查看组件:pip show fastapi

Name: fastapi Version: 0.139.0 Summary: FastAPI framework, high performance, easy to learn, fast to code, ready for production Home-page: https://github.com/fastapi/fastapi Author:  Author-email: =?utf-8?q?Sebasti=C3=A1n_Ram=C3=ADrez?= <tiangolo@gmail.com> License-Expression: MIT Location: D:\\workspace3\\python\\venv_project\\.venv\\Lib\\site-packages Requires: annotated-doc, pydantic, starlette, typing-extensions, typing-inspection Required-by: 

已安装的包导出到文件:pip freeze > requirements.txt

新环境安装所有依赖:pip install -r requirements.txt

退出虚拟环境

deactivate

退出后,命令行提示符会恢复正常,Python 和 pip 命令将使用系统全局版本。

删除虚拟环境

虚拟环境本质上是一个普通目录,删除目录即彻底移除:

rmdir /s /q .venv

注意:删除前请先执行 deactivate 退出环境,否则当前 Shell 会保留失效的环境变量。

Uvicorn 

Uvicorn 是一个基于 ASGI(异步服务器网关接口)的 Python Web 服务器,常与 FastAPI 等现代异步框架搭配使用。它的操作主要围绕安装、运行和配置展开。

安装

# 安装基础版本 pip install uvicorn

# 推荐:安装标准版本(包含 uvloop, httptools 等性能优化组件和开发工具) pip install 'uvicorn[standard]'

启动

python -m uvicorn main:app –reload

FAstAPI &SQLAlchemy 示例

main.py

# 教程:https://www.runoob.com/fastapi/fastapi-tutorial.html

from fastapi import FastAPI

app = FastAPI()

# GET http://127.0.0.1:8000/
@app.get("/")
async def root():
return {"message": "Hello World"}

# GET http://127.0.0.1:8000/items/11?q1=12
# OUT: {"item_id":11,"q":"12","p2":"p22"}
# q1: str = None 可以没有
# p2:str = "p22" 字符串 默认p22
@app.get("/items/{item_id}")
def read_item(item_id: int, q1: str = None,p2:str = "p22"):
return {"item_id": item_id, "q": q1 ,"p2":p2}

# 路由处理函数返回一个 Pydantic 模型实例,FastAPI 将自动将其转换为 JSON 格式,并作为响应发送给客户端:
from pydantic import BaseModel

class Item(BaseModel):
name:str
age:int = None

# POST http://127.0.0.1:8000/items1
# Body:{
# "name": "123123啊啊啊",
# "age": 1111
# }
@app.post("/items1")
def items1(item:Item):
print("items1:",item.age,item.name)
print(item.model_dump()) # {'name': 'string111', 'age': 123}
print(item.model_dump_json()) # {"name":"string111","age":123}
return item

# 请求头和 Cookie
# 使用 Header 和 Cookie 类型注解获取请求头和 Cookie 数据。
from fastapi import Header, Cookie
# {
# "User-Agent": "PostmanRuntime/7.1.1",
# "Session-Token": null
# }
@app.get("/item2")
def item2(user_agent: str = Header(None), session_token: str = Cookie(None)):
return {"User-Agent": user_agent, "Session-Token": session_token}

# 重定向
# 使用 RedirectResponse 实现重定向,将客户端重定向到 /item2/ 路由。
from fastapi.responses import RedirectResponse
@app.get("/redirect")
def redirect():
return RedirectResponse(url="/item2/")

# 设置状态码
from fastapi import HTTPException
@app.get("/items1/{item_id}")
def read_item(item_id: int):
if item_id == 42:
raise HTTPException(status_code=404, detail="Item not found")
return {"item_id": item_id}
# OUT : 404
# {
# "detail": "Item not found"
# }

# 自定义响应头
from fastapi.responses import JSONResponse
@app.get("/default_header")
def default_header():
content = {"item_id": 1000,"body":10001}
headers = {"X-Custom-Header": "custom-header-value1111111111"}
return JSONResponse(content=content, headers=headers)

# Pydantic 模型支持继承,可以方便地创建输入模型和输出模型:
from pydantic import BaseModel, EmailStr
class UserBase(BaseModel):
username: str # 必填
email: EmailStr # 必填,自动校验邮箱格式
full_name: str | None = None # 可选

# 创建用户时的输入模型(包含密码)
class UserCreate(UserBase):
password: str # 必填

# 返回用户信息时的输出模型(不包含密码)
class UserOut(UserBase):
id: int # 由服务器生成

@app.post("/users/", response_model=UserOut)
async def create_user(user: UserCreate):
# 函数接收 UserCreate(含密码),但响应使用 UserOut(不含密码)
# 这样密码就不会出现在 API 响应中
# <bound method BaseModel.model_dump_json of UserCreate(username='string111', email='user@example22.com', full_name='string333', password='string444')>
print(user.model_dump_json)
return {"id": 1, **user.model_dump(exclude={"password"})}

# form
from fastapi import FastAPI, Form
@app.post("/login/")
async def login(
username: str = Form(), # 必填表单字段
password: str = Form(), # 必填表单字段
):
print(f"{password=}")
return {"username": username}

@app.post("/items/")
async def create_item(
name: str = Form(…), # 必填
description: str | None = Form(None), # 可选,默认 None
price: float = Form(…, gt=0), # 必填,必须大于 0
):
return {"name": name, "description": description, "price": price}

# router
from fastapi import APIRouter, Depends, HTTPException, Request
router = APIRouter(
prefix="/posts", # 所有路由自动加上 /posts 前缀
tags=["文章"] # Swagger 文档中的分组标签
)

# 挂载 APIRouter:
app.include_router(router)

@router.get("/{post_id}", response_model=None, name="post_detail")
def post_detail(post_id: int):
"""文章详情 """
return {"post_id":post_id}

# 导入数据库配置
import database,models

# 文件路径:main.py 启动事件中创建表
from fastapi import FastAPI
from database import engine, Base
from models import Category, Post # 确保模型类被导入,Base.metadata 才能识别
@app.on_event("startup")
def on_startup():
"""应用启动时自动创建数据库表(仅开发使用,只要有对应表名称对,那么就不需要重新创建)"""
Base.metadata.create_all(bind=engine)

#执行SQL
# 参考:https://blog.csdn.net/weixin_42743844/article/details/156913924
import seed
@app.post("/insert_data")
async def insert_data():
seed.exec()
return "success…"

database.py

from sqlalchemy import create_engine

# MySQL连接字符串格式:mysql+pymysql://用户名:密码@主机:端口/数据库名
# 注意:首次连接需要先在MySQL中创建数据库(比如test_db)
engine = create_engine('mysql+pymysql://root:123456@localhost:3306/pythondb',
echo=True, # 打印执行的SQL(调试用,上线关闭)
pool_size=5, # 连接池大小(默认5)
max_overflow=10 # 超出连接池后的最大连接数(默认10)
)

# 测试连接(无报错则成功)
with engine.connect() as conn:
print("连接成功!")

# =============================

# 创建会话工厂
from sqlalchemy.orm import sessionmaker
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

# 创建BaseModule类型
from sqlalchemy.orm import declarative_base,DeclarativeBase

Base = declarative_base()
# Base 类:所有 ORM 模型继承自它
class Base1(DeclarativeBase):
pass

# =============================
from fastapi import Depends

def get_db():
"""FastAPI 依赖注入:为每个请求创建独立的数据库会话"""
db = SessionLocal()
try:
yield db # 请求期间使用这个会话
finally:
db.close() # 请求结束后自动关闭会话,防止连接泄漏

models.py

# 文件路径:models.py
from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey
from sqlalchemy.orm import relationship
from datetime import datetime
from database import Base

class Category(Base):
"""文章分类"""
__tablename__ = "categories"
id = Column(Integer, primary_key=True, index=True)
name = Column(String(50), unique=True, nullable=False)
slug = Column(String(50), unique=True, nullable=False)
# back_populates 双向关系
posts = relationship("Post", back_populates="category")

class Post(Base):
"""博客文章"""
__tablename__ = "posts"
id = Column(Integer, primary_key=True, index=True)
title = Column(String(200), nullable=False)
slug = Column(String(200), unique=True, nullable=False)
summary = Column(Text, default="")
content = Column(Text, nullable=False)
category_id = Column(Integer, ForeignKey("categories.id"), nullable=False)
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# 与 Category 的双向关系
category = relationship("Category", back_populates="posts")

启动Server

命令:python -m uvicorn main:app –reload

INFO:     Will watch for changes in these directories: ['D:\\\\workspace3\\\\python\\\\fastapi'] INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) INFO:     Started reloader process [1780] using WatchFiles 2026-07-06 16:49:18,153 INFO sqlalchemy.engine.Engine SELECT DATABASE() 2026-07-06 16:49:18,153 INFO sqlalchemy.engine.Engine [raw sql] {} 2026-07-06 16:49:18,154 INFO sqlalchemy.engine.Engine SELECT @@sql_mode 2026-07-06 16:49:18,155 INFO sqlalchemy.engine.Engine [raw sql] {} 2026-07-06 16:49:18,155 INFO sqlalchemy.engine.Engine SELECT @@lower_case_table_names 2026-07-06 16:49:18,156 INFO sqlalchemy.engine.Engine [raw sql] {} 连接成功! INFO:     Started server process [6140] INFO:     Waiting for application startup. 2026-07-06 16:49:18,290 INFO sqlalchemy.engine.Engine BEGIN (implicit) 2026-07-06 16:49:18,290 INFO sqlalchemy.engine.Engine DESCRIBE `pythondb`.`categories` 2026-07-06 16:49:18,290 INFO sqlalchemy.engine.Engine [raw sql] {} 2026-07-06 16:49:18,292 INFO sqlalchemy.engine.Engine DESCRIBE `pythondb`.`posts` 2026-07-06 16:49:18,292 INFO sqlalchemy.engine.Engine [raw sql] {} 2026-07-06 16:49:18,294 INFO sqlalchemy.engine.Engine COMMIT INFO:     Application startup complete.

访问 API Doc

http://127.0.0.1:8000/docs

执行:


如果这篇文章对你有帮助,欢迎点赞、收藏、转发!有任何疑问或想深入探讨某个框架,评论区见!

赞(0)
未经允许不得转载:171主机测评 » Python 虚拟环境 virtualenv & uvicorn 服务搭建 & FAstAPI 使用
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址