【问题标题】:Stop a M2M relationship being saved in django停止在 django 中保存 M2M 关系
【发布时间】:2012-01-22 16:37:05
【问题描述】:

我有一个 AdminModel,它允许用户在任何字段留空的情况下进行保存。但是,我不希望他们能够在所有字段都为空时保存。我已经使用以下方法实现了这一点:

def save_model(self, request, obj, form, change):
    if form.has_changed():
        obj.save()
    else:
        pass

但是,该模型与另一个模型具有 M2M 关系,因此当我点击保存时出现以下错误:

instance needs to have a primary key value before a many-to-many relationship can be used.

我需要在这个方法中添加什么来阻止它尝试创建 M2M 关系?

编辑:

我添加了 hacky 解决方法,但我很想知道是否有更好的方法。解决方法是更改​​else,使其更改ModelAdmin 的字段属性,使其不包含M2M 关系的字段——这可以防止它尝试建立关系。这不仅是hacky,而且只有在保存模型一次失败并抛出错误后才有效......

【问题讨论】:

  • 如果失败,则不是解决方案。此外,该解决方案不是线程安全的。
  • 我知道,我只是想弄清楚是否有办法做我想做的事。我是 django 的新手,所以我只是在尝试。

标签: django


【解决方案1】:

你不能 - save_m2msave_model 之后被调用。文档特别说这个钩子是not for veto purposes.

ModelAdmin.save_model() 和 ModelAdmin.delete_model() 必须保存/删除 对象,它们不是用于否决目的,而是允许您 执行额外的操作。

您需要的是表单验证来防止save_model 被触发。不知何故,您需要检测所有字段何时留空。

class MyForm(forms.ModelForm):
    class Meta:
        model = MyModel

    def clean(self):
        if not any(self.cleaned_data.values()):
            raise forms.ValidationError("All fields cannot be blank!")
        return self.cleaned_data

class MyAdmin(admin.ModelAdmin):
    form = MyForm

【讨论】:

  • 我不知道any()。非常有用。
  • @pastylegs anyall! PS:在 WP 上看到你了!
【解决方案2】:

最好在表单级别而不是管理员级别进行验证。为此,请创建一个自定义 Form 类以供您的 ModelAdmin 使用。所以创建一个forms.py

from myapp.models import MyModel
from django import forms

class MyModelForm(forms.ModelForm):
    pass

    class Meta:
        model = MyModel

    def clean(self):
        empty = True
        for field_name, field_data in self.cleaned_data.iteritems():
            if field_data:
                empty = False
        if empty:
            raise forms.ValidationError("The form cannot be empty")
        return self.cleaned_data

并允许您的管理员使用此表单。在admin.py

from myapp.forms import MyModelForm
from django.contrib import admin

class MyModelAdmin(admin.ModelAdmin):
    ...
    form = MyModelForm

【讨论】:

  • 我必须将 field_data in self.cleaned_data 更改为 for field_name, field_data in self.cleaned_data.iteritems() 才能使其正常工作,但这正是我想要的,并且得到了非常清楚的解释。谢谢!
  • 顺便说一句,Yuji 检查字段是否为空的解决方案可能更简洁
  • 你是对的 - 我会那样做。每个人都因乐于助人而获得代表:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-07
  • 2020-06-18
  • 2014-08-16
  • 2023-03-13
  • 1970-01-01
相关资源
最近更新 更多