Python 现代开发学习笔记

(十六)当前用户、CRUD 视图与事务结果

1. 成功保存与失败回显

# 续写同一文件:reading_project/src/library/views.py
def book_form(request, book=None):
    # POST 即使为空也要绑定,让 required 字段给出错误。
    form = BookForm(
        request.POST if request.method == "POST" else None,
        instance=book,
        user=request.user,
    )
    status = 200
    if request.method == "POST":
        status = 422
        if form.is_valid():
            try:
                saved = save_book(form, request.user)
            except IntegrityError as exc:
                if (
                    getattr(exc.__cause__, "sqlite_errorname", "")
                    != "SQLITE_CONSTRAINT_UNIQUE"
                ):
                    raise
                # 在 atomic 外处理异常;本次事务已经回滚。
                form.add_error(None, "保存时发生同名冲突,请修改后重试")
                status = 409
            else:
                messages.success(request, "已保存阅读记录")
                return redirect("library:detail", pk=saved.pk)
    return render(
        request, "library/book_form.html", {"form": form, "book": book}, status=status
    )


@login_required
def create(request):
    return book_form(request)


@login_required
def edit(request, pk):
    return book_form(request, owned_book(request.user, pk))


@login_required
@require_POST
def delete(request, pk):
    with transaction.atomic():
        owned_book(request.user, pk).delete()
    messages.success(request, "已删除书籍")
    return redirect("library:index")

book_form 处理新增和修改共用的表单过程。GET 不绑定,POST 绑定实际提交;字段错误交回 422。通过后进入 save_book,事务成功再暂存消息并跳详情;数据库实际写入发生唯一键冲突时,事务已回滚,表单加入整体错误并返回 409。

正常的重名通常在 clean_title 阶段发现。两个请求可能都先通过检查,再先后写入,数据库唯一约束继续处理后一份冲突,这也是表单检查与数据库约束同时保留的原因。

2. 登录检查之后还要核对书籍

owned_book 查记录后比较 owner_id,其他用户得到 403。新增的归属来自 request.user,修改时仍检查原记录归属。删除同时使用 login_required 和 require_POST,GET 删除入口得到 405。

同一表单 GET 显示或 POST 校验,字段错保留输入,实际写入冲突回滚后回填,成功提交再跳详情;编号操作继续检查记录归属

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