日度归档:2025年6月21日

32 ORM之多对多添加记录

多对多关系,会有一张新的表进行存储,这里我们接上回,添加学生的时候,需要把学生选的课程一并添加到数据库中。

@students.post('/students')
async def add_students(student_in: StudentIn):
    # 插入数据

    # 方式二
    student = await Student.create(name=student_in.name,pwd=student_in.pwd,student_number=student_in.student_number,classes_id=student_in.classes_id)

    # 添加多对多记录
    courses = await Courses.filter(id__in=student_in.courses)
    print("courses", courses)
    await student.courses.add(*courses)
    print("student", student.courses)

    return student

courses = await Courses.filter(id__in=student_in.courses)
这句就是在课程表中过滤学生选的课程id

await student.courses.add(*courses)
这句就是将学生选的课,一行一行插入到多对多关系表中

比如,我添加一个学生kuxie,除了基本信息外,他还选了id是6和7的课程(在courses表中可以查看)。
在文档中测试:
file
点击execute后,查看各表:
student表:
file
courses表:
file
多对多关系表:
file
学生和选的课程关系存储成功。

31 ORM 添加表记录

FastAPI tortoise ORM添加数据,在此接口方法下实现:
方式一:

@students.post('/students')
async def add_students(stu: Student):
    return {"msg": "添加学生"}

传入json,并且做校验

class StudentIn(BaseModel):
    # id : int  # 可以不传
    name: str
    pwd: str
    student_number: int
    # 在数据库中,这个字段就变成了classes_id
    classes_id: int
    courses: List[int] = []

    @field_validator('name')
    @classmethod
    def name_must_not_be_empty(cls, v):
        if not v:
            raise ValueError('Name cannot be empty')
        return v

@students.post('/students')
async def add_students(student_in: StudentIn):
    # 插入数据
    # 方式一
    # 先实例化
    student = Student(name=student_in.name,pwd=student_in.pwd,student_number=student_in.student_number,classes_id=student_in.classes_id)
    # 这里的classes_id就是一对多的传参了
    # 然后存入数据库
    await student.save()

    return "添加了一个学生"

id我们之前设置过,是自增的:

mysql> desc student;
+----------------+-------------+------+-----+---------+----------------+
| Field          | Type        | Null | Key | Default | Extra          |
+----------------+-------------+------+-----+---------+----------------+
| id             | int         | NO   | PRI | NULL    | auto_increment |
| name           | varchar(32) | NO   |     | NULL    |                |
| pwd            | varchar(32) | NO   |     | NULL    |                |
| student_number | int         | NO   |     | NULL    |                |
| classes_id     | int         | NO   | MUL | NULL    |                |
+----------------+-------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)

方式二:

@students.post('/students')
async def add_students(student_in: StudentIn):
    # 方式二
    student = await Student.create(name=student_in.name,pwd=student_in.pwd,student_number=student_in.student_number,classes_id=student_in.classes_id)

    return student

以上代码的测试,都可以通过FastAPI自带的接口文档进行测试。

30 ORM响应页面数据

前后端分离的场景下,用户访问的是前端服务器,后端开发的接口是给前端用的,这个要谨记。

了解一下前后端不分离的模式

@student.get("/index.html")
async def getAllStudent():
    students = await Student.all()
    return students

这里直接返回的话,返回的是json的数据,可以在接口文档中看的很清楚。

前后端不分离的话,我们需要将数据嵌入前端中,然后返回给用户。

# 需要导入jinja2
from fastapi.templating import Jinja2Templates
from fastapi import Request

@students.get('/students')
async def get_all_students(request: Request):  # 这里必须携带Request的实例
    all_students = await Student.all()
    templates = Jinja2Templates(directory=r".\chapter3\学习ORM\apis\templates")

    return templates.TemplateResponse(
        "index.html",{            # 模板文件写这里
        "request": request,
        "students": all_students  #传递的参数写这里
        }
    )

模板文件需要在合适的位置编辑好,数据插入的位置,类似这样

<html>
  <body>
    <ul>
      {% for student in students %}
          <li>姓名:{{ student.name }}, 学号:{{ student.student_number }}</li>
      {% endfor %}
    </ul>
  </body>
</html>

再尝试访问,就可以看到返回的渲染后的页面了
file
然后 老师讲了一下bootstrap的一些用法,看看就好。