ModelForm 保存多对多是先清空再重建吗?取消全部勾选会怎样?有额外字段的 through 表能用表单保存吗?这篇看每种情形的 SQL。
UPDATE "lab_post" SET "title" = 'p' WHERE "lab_post"."id" = 1
BEGIN
SELECT "lab_tag"."id" AS "id" FROM "lab_tag" INNER JOIN "lab_post_tags" ON ("lab_tag"."id" = "lab_post_tags"."tag_id") W
DELETE FROM "lab_post_tags" WHERE ("lab_post_tags"."post_id" = 1 AND "lab_post_tags"."tag_id" IN (1))
INSERT OR IGNORE INTO "lab_post_tags" ("post_id", "tag_id") VALUES (1, 3)
COMMIT
之后 tags = ['b', 'c']并发场景下这比「先全删再全建」更友好:没变的关系行不会被删除又重建(不会短暂消失)。
is_valid = True
没提交 tags 字段(等同于全部取消勾选)后 tags = []
required=True 时: {'tags': ['required']}把「不勾选」当作「清空」是符合直觉的,但如果前端漏渲染了这个字段,保存就会清空用户已有的关系——所以 fields 白名单里的多对多字段一定要在模板里渲染。
含不存在的 id: {'tags': [('invalid_choice', {'value': 99999})]}
不在 queryset 里的 id(d): {'tags': ['invalid_choice']}用 queryset 限制用户能关联到哪些对象(比如只能选自己的标签)。
TeamForm 字段: ['name', 'members']
Team.members 的 through 是自定义模型: Membership
TeamForm 提交 members:is_valid = True
save() 成功;SQL:
INSERT INTO "lab_team" ("name") VALUES ('t2') RETURNING "lab_team"."id"
BEGIN
SELECT "lab_member"."id" AS "id" FROM "lab_member" INNER JOIN "lab_membership" ON ("lab_member"."id" = "lab_membership".
SELECT "lab_membership"."member_id" AS "member" FROM "lab_membership" WHERE ("lab_membership"."member_id" IN (1) AND "la
INSERT INTO "lab_membership" ("member_id", "team_id", "role") VALUES (1, 2, 'dev') RETURNING "lab_membership"."id"
COMMIT
Membership 里的行: [('m1', 'dev')] (role 用 default)Django 允许对自定义 through 模型的多对多使用 add()/set(),前提是额外字段都有默认值(或用 through_defaults 指定)。