Python 现代开发学习笔记

(七)外键、多对多与中间表

一本书只属于一个用户,一个用户可以有多本书,ForeignKey 在书籍表保存 owner_id。book.owner 返回关联用户对象,book.owner_id 直接读取编号。on_delete=CASCADE 表示用户删除时,一并删除它的书。

一本书可以有多个标签,同一个“工程”标签也可以用于不同的书。ManyToManyField 创建关联中间表,每行保存书籍编号与标签编号。标签在这章作为共享分类名称;用户的具体书籍和备注仍按归属隔离。

用户编号写入书籍外键,书籍与标签通过中间表逐行关联,同一个工程标签对应两本不同用户的书,不复制标签名称记录

book.tags.add(tag) 添加关联,book.tags.set(tags) 把当前关联替换为这份列表。中间表需要两侧主键,因此新书先 save() 取得编号,再保存标签。下面的实际演示也检查模型字段:

# 项目文件:demos/model_steps.py
from lab import lab

with lab():
    from django.contrib.auth import get_user_model
    from django.core.exceptions import ValidationError

    from library.models import Book, Tag

    alice = get_user_model().objects.get(username="alice")
    book = Book(owner=alice, title="ORM 实践")
    print("构造后", book.pk)
    book.full_clean()  # 主动执行模型校验;save 本身不会自动调用它。
    book.save()
    print("保存后有编号", book.pk is not None)
    tag, created = Tag.objects.get_or_create(name="框架")
    book.tags.add(tag)  # 取得书籍编号后,才能保存中间表的关联。
    print("关联标签", list(book.tags.values_list("name", flat=True)))
    invalid = Book(owner=alice, title="x" * 101)
    try:
        invalid.full_clean()
    except ValidationError as error:
        print("模型错误字段", list(error.message_dict))

save() 负责持久化,不会自动调用 full_clean()。表单会执行相关校验,直接用 ORM 导入数据时可以主动调用 full_clean;组合唯一约束还会由数据库在实际写入时检查。

笔记正文与全部题解 · Ctrl / ⌘ K