django - Django通过表自定义ManyToMany关系:模型表单保存(或save_m2m)期间未调用保存方法
问题描述
这是设置...
class RequestUserBaseClass(Model):
# There is middleware that sets "thread.request" with each request - that is functioning fine
thread = threading.local()
created_by = ForeignKey(User)
...
def save(self, *args, **kwargs):
self.created_by = RequestUserBaseClass.thread.request.user
...
class Meta:
abstract = True
class CustomThroughTable(RequestUserBaseClass):
...
class SimpleModelClass(RequestUserBaseClass):
...
manyfield = ManyToManyField(OtherTable, through=CustomThroughTable)
...
class SimpleModelForm(ModelForm):
class Meta:
model = SimpleModelClass
fields = [... 'manyfield' ... ]
在视图中...
if simple_form.is_valid():
simple_form.save()
底线:我有这个基类,它通过与一些将用户置于线程局部变量中的自定义中间件一起工作来设置由字段创建。效果很好,到处使用。
然后我有一个ManyToManyField
使用自定义直通表的模型。当表单被保存时,我收到一个关于created_by_id
未设置的完整性错误,并且通过检查输出,这是将直通表中的条目添加到数据库中的时间。这是因为我只在ManyToManyField
编辑后才收到错误。如果我这样做simple_form.save(commit=False)
然后simple_form.save_m2m()
单独打电话,那么我会在通话中遇到IntegrityError
异常save_m2m()
。
为什么会这样呢?save()
添加通过表条目或其他内容时不会被调用吗?
如果您认为出于某种原因需要它,请随时询问更多信息。我有空而且很难过......
更新:
我确认save()
没有在自定义表格模型上调用它(只是添加了一个raise Exception('DEBUG')
并且它从未被击中)。我想这只是意味着我需要手动保存我的 m2m 字段而不是使用该ModelForm#save()
方法。在这一点上,我想我只是想知道是否有任何 Django 大师同意这种方法,或者认为它是我遇到的 Django 错误。
解决方案
好吧,永远无法确认这是否是 Django 错误,但我确实设法解决了(可能是真正的解决方法)这个问题。基本上只需要在视图中执行以下操作:
if simple_form.is_valid():
form_data = deepcopy(simple_form.cleaned_data)
# pop out m2m
manyfield = form_data.pop("manyfield", [])
# set non m2m fields
for key, val in form_data.items():
setattr(simple_model_instance, key, val)
# Need to create through entries directly so that the throughclass#save()" gets called and sets created_by
for manyentry in manyfield:
CustomThroughTable.objects.get_or_create(...)
simple_model_instance.save()
本质上:手动将表单数据应用于现有实例,然后通过表条目手动创建自定义,以便调用它们的保存方法(在我的具体示例中,因此调用抽象父级的保存方法并设置 created_by 属性)
推荐阅读
- r - 删除/选择一些在R中名称末尾带有序列号的对象
- tensorflow - 将权重图输入 keras 中的 CNN(UNET 网络)
- javascript - 使用 JavaScript 如何禁用右键单击或单击滚动条时如何在右键单击窗口中删除检查元素选项
- powershell - 我想用所有 Azure AD 应用程序创建一个输出,它返回 a) 全部列表 b) 过期应用程序列表
- build - Next.js CLI - 在本地运行 dev 时是否可以预先构建某些路由?
- php - PHPMailer 与 Ajax 示例我有错误 Uncaught (in promise) TypeError: error.json is not a function
- css - 在为 React 组件设置动画时获得预期的赋值或函数调用
- c++ - 将简单的加密 LDB 文件读取到文本文件
- python - 如何创建“每周箱线图”?
- snowflake-cloud-data-platform - 当我将代码放在 TRY CATCH 块中并故意在存储过程定义 - 雪花中引入错误时,变量未找到错误