一 构建一个原始的服务端了解网站原理
浏览器向服务端发送一个请求,请求格式依照http协议,具有请求地址,请求头,请求体
利用python构建一个服务端依据http协议格式返回字节数据,浏览器会根据协议解析数据并展现内容
import socket
sock = socket.socket()
sock.bind(("127.0.0.1",9999))
sock.listen(5)
while True:
conn, addr = sock.accept()
data = conn.recv(1024)
print("获取到的数据为:\n", data)
conn.send(b"HTTP/1.1 200 OK\nserver:liu\n\nhaole")
conn.close()
此时访问127.0.0.1:9999这个地址,浏览器会自动附带一些基础数据向我们的服务端发起请求,服务端会收到这些请求信息
然后向浏览器发送我们固定写好的信息haole
restful接口开发规范
| 请求方法 | 请求地址 | 请求规范 |
|---|---|---|
| get | /student | 获取所有学生 |
| post | /student | 增加学生 |
| delete | /student/1 | 删除学生 |
| put | /student/1 | 修改学生 |
二 fastapi简单案例
import uvicorn
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def home():
return {"Hello": "World"}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
此时访问127.0.0.1:8000即可获取到返回的json数据
三 路径操作
3.1 路径操作装饰器
@app.get("/home")
@app.post("/post")
@app.put("/update")
@app.delete("/delete")
3.1.1 路径操作装饰器方法参数
tags:总标题summary:总结description:描述response_description:返回描述
3.2 include_router
在单独一个模块里面的文件中编写接口
在主文件中通过include_router导入
四 请求与响应
4.1 路径参数
4.2 查询参数
4.3 请求体数据
使用pydantic中BaseModel进行数据类型校验
import uvicorn
from fastapi import FastAPI
from pydantic import BaseModel, Field, field_validator
from datetime import date
from typing import List, Union, Optional
app = FastAPI()
class User(BaseModel):
name: str
age: int = Field(default=0, ge=0, le=100)
birth: Union[None, date] = None
friends: List[int] = []
description: Optional[str] = None
@field_validator('name')
def name_mustbe_alpha(cls, value):
assert value.isalpha(), "名字必须为字母"
return value
@app.post('/user')
def user(user: User):
print(user.name)
return user
if __name__ == "__main__":
uvicorn.run("quickstart:app", host="0.0.0.0", port=8000, reload=True)
4.4 文件上传
4.4.1 小文件上传
1. 单个文件上传
@app.post('/file')
async def getfile(file: bytes = File()):
# 适合小文件上传
print(file)
print(len(file))
return {
"status": "success",
}
2. 多个文件上传
@app.post('/files')
async def getfiles(files: List[bytes] = File()):
# 适合小文件上传
for file in files:
print(len(file))
return {"length": len(files)}
4.4.2 大文件上传
import uvicorn
from fastapi import FastAPI, UploadFile
app = FastAPI()
@app.post("/uploadFile")
def upload_file(file: UploadFile):
with open(file.filename, "wb") as f:
f.write(file.file.read())
return {"status": True}
if __name__ == "__main__":
uvicorn.run("quickstart:app", host="127.0.0.1", port=8000, reload=True)
4.5 request对象
查看客户端请求时的数据
@app.post("/request")
async def re(request: Request):
headers = dict(request.headers)
query = dict(request.query_params)
body = await request.body() # 原始请求体
return {"headers": headers, "query": query, "body": body.decode()}
得到的结果如下
{
"headers": {
"host": "127.0.0.1:8000",
"connection": "keep-alive",
"content-length": "0",
"sec-ch-ua-platform": "\"Windows\"",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0",
"accept": "application/json",
"sec-ch-ua": "\"Microsoft Edge\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
"sec-ch-ua-mobile": "?0",
"origin": "http://127.0.0.1:8000",
"sec-fetch-site": "same-origin",
"sec-fetch-mode": "cors",
"sec-fetch-dest": "empty",
"referer": "http://127.0.0.1:8000/docs",
"accept-encoding": "gzip, deflate, br, zstd",
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6"
},
"query": {},
"body": ""
}
五 ORM对象关系模型
5.1 ORM创建模型类
导入tortoise-orm库
pip install tortoise-orm
建立一个简单的models.py用于编写数据库类
from tortoise.models import Model
from tortoise import fields
class Student(Model):
id = fields.IntField(pk=True)
name = fields.CharField(max_length=32,description="学生姓名")
pwd = fields.CharField(max_length=32,description="学生密码")
son = fields.IntField(max_length=32,description="学生学号")
# 一对多
cls = fields.ForeignKeyField("models.Cls", related_name="students")
# 多对多
curses = fields.ManyToManyField("models.Curse", related_name="students")
class Cls(Model):
id = fields.IntField(pk=True)
name = fields.CharField(max_length=32)
class Course(Model):
id = fields.IntField(pk=True)
name = fields.CharField(max_length=32)
teacher = fields.ForeignKeyField("models.Teacher", related_name="courses")
class Teacher(Model):
id = fields.IntField(pk=True)
name = fields.CharField(max_length=32)
tno = fields.IntField(max_length=32)
编写数据库配置文件
TORTOISE_ORM = {
"connections": {
"default": {
"engine": "tortoise.backends.mysql",
"credentials": {
"user": "root",
"password": "",
"host": "127.0.0.1",
"database": "fastapi_demo",
"port": 3306,
"maxsize": 5,
"minsize": 1,
"charset": "utf8mb4",
"echo": True
}
}
},
"apps": {
"models":{
"models": ["models"],
"default_connection": "default",
}
},
"use_tz": False,
"timezone": "Asia/Shanghai",
}
在main.py中编写监听数据库代码
import uvicorn
from fastapi import FastAPI
from tortoise.contrib.fastapi import register_tortoise
from orm import TORTOISE_ORM
app = FastAPI()
register_tortoise(
app=app,
config=TORTOISE_ORM
)
if __name__ == "__main__":
uvicorn.run("quickstart:app", host="127.0.0.1", port=8000, reload=True)
5.2 ORM的迁移命令 aerich迁移工具
在终端中通过pip安装aerich:
pip install aerich
然后安装aiomysql:
pip install aiomysql
初始化配置文件:
aerich init -t orm.TORTOISE_ORM
初始化数据库:
aerich init-db
models更新后可以使用以下命令生成新的迁移文件:
aerich migrate
aerich upgrade
aerich downgrade
5.3 利用orm对数据库进行增删改查以及响应页面数据
5.3.1 查询数据
简单查询
@app.get("/students")
async def get_students():
# 1)查询所有,返回一个Queryset
students = await Student.all()
for student in students:
print(student.name, student.pwd)
# 2)过滤查询filter,返回一个Queryset
stus = await Student.filter(cls_id=3)
# 3)过滤查询get,返回第一个符合条件的对象
stu = await Student.get(name="张三")
# 4)模糊查询
stusGt20002 = await Student.filter(son__gte=20002)
stusbetween = await Student.filter(son__range=[20001, 20002, 20003])
stusin = await Student.filter(son__in=[20001, 20003])
# 5) values查询
stuNameAndSon = await Student.all().values("name", "son") #[{"name":"张三","son":20001}, {...}. {...}]
return {
"message": "get all student data"
}
查询一对多外联表信息
@app.get("/student")
# 查询外联表cls中id为zhang:cls_id的name字段
async def get_student_clsname():
# 使用await得到的是查询结果,[Student对象, Student对象, ...]
zhang1 = await Student.get(name="张三")
# 不使用await得到一个查询链对象描述要查询的信息,<QuerySet对象>
zhang2 = Student.filter(name="张三")
# 获取学生对象cls外联表中的信息
classname1 = await zhang1.cls.values("name")
# 完善动作链再执行查询操作
classname2 = await zhang2.values("cls__name")
return {
"方式一": classname1,
"方式二": classname2
}
查询多对多外联表
@app.get("/student")
async def get_student_cursesname():
# 使用 prefetch_related 预加载多对多关系
students = await Student.all().prefetch_related("curses")
result = []
for student in students:
# 现在可以直接访问 curses,因为已经预加载了
courses = student.curses
result.append({
"student_name": student.name,
"courses": [{"id": course.id, "name": course.name} for course in courses]
})
return result
5.3.2 响应页面数据
使用JinJa2返回一个html界面
import uvicorn
from fastapi import FastAPI
from tortoise import Tortoise
from tortoise.contrib.fastapi import register_tortoise
from models import Student
from orm import TORTOISE_ORM
# 响应界面所需库
from fastapi.templating import Jinja2Templates
from fastapi import Request
app = FastAPI()
register_tortoise(
app=app,
config=TORTOISE_ORM
)
@app.get("/students")
async def get_students(request: Request):
templates = Jinja2Templates(directory="templates")
students = await Student.all()
return templates.TemplateResponse(
"index.html", {
"request": request,
"students": students
}
)
if __name__ == "__main__":
uvicorn.run("quickstart:app", host="127.0.0.1", port=8000, reload=True)
5.3.3 增加数据
from typing import List
import uvicorn
from fastapi import FastAPI
from pydantic import BaseModel, field_validator
from tortoise.contrib.fastapi import register_tortoise
from models import Student, Course
from orm import TORTOISE_ORM
app = FastAPI()
register_tortoise(
app=app,
config=TORTOISE_ORM
)
class StudentIn(BaseModel):
name: str
pwd: str
son: int
cls: int
curses: List[int] = [1, 2]
@field_validator("name")
def check_name(cls, v):
assert v.isalpha(), "name must be alphanumeric"
return v
@app.post("/student")
async def add(stu: StudentIn):
# 插入方式一
newstudent = Student(name=stu.name, pwd=stu.pwd, son=stu.son, cls_id=stu.cls)
await newstudent.save()
# 插入方式二
newstudent = await Student.create(name=stu.name, pwd=stu.pwd, son=stu.son, cls_id=stu.cls)
# 多对多形式插入
student_courses = await Course.filter(id__in=stu.curses)
await newstudent.curses.add(*student_courses)
return newstudent
5.3.4 更新数据
@app.put("/student/{stu_id}")
async def update_student(stu_id: int, stu: StudentIn):
# 将传进的数据转化为json格式
new_date = stu.model_dump()
# 将传进来的数据中属于多对多关联表中的curses_id部分弹出给curses_date,后面单独添加
curses_date = new_date.pop("curses")
# 使用filter中自带的update方法更新数据,需要解构
await Student.filter(id=stu_id).update(**new_date)
'''
下面是多对多数据添加部分
1. 获取要编辑的学生对象
2. 清除该对象中原先关联的curses数据
3. 将之前获取到的curses_date转化为curses对象集合
4. 将curses对象集合通过get的add方法添加进关联表
'''
# 获取要编辑的学生
edit_stu =await Student.get(id=stu_id)
# 清除旧数据
await edit_stu.curses.clear()
# 将传递进来的json实例化课程对象
choose_cursor =await Course.filter(id__in=curses_date)
# 将课程对象添加到编辑的学生对象的多对多关联表中
await edit_stu.curses.add(*choose_cursor)
return stu_id
5.3.5 删除数据
会将关联数据库中的信息一起删除
@app.delete("/student/{stu_id}")
async def delete_student(stu_id: int):
await Student.filter(id=stu_id).delete()












暂无评论