【问题标题】:Django admin site modify saveDjango 管理站点修改保存
【发布时间】:2024-01-07 15:10:01
【问题描述】:

在管理站点中,我有一个自定义表单。但是,我想重写 save 方法,这样如果输入了某个关键字,我就不会将其保存到数据库中。这可能吗?

class MyCustomForm (forms.ModelForm):

    def save(self, commit=True):
        input_name = self.cleaned_data.get('input_name', None)
        if input_name == "MyKeyword":
             //Do not  save
        else:
            return super(MyCustomForm, self).save(commit=commit)

但这会返回错误:

 AttributeError 'NoneType' object has no attribute 'save' 

编辑 在此之后:Overriding the save method in Django ModelForm

我试过了:

def save(self, force_insert=False, force_update=False, commit=True):
    m = super(MyCustomCategoryForm, self).save(commit=False)
    input_name = self.cleaned_data.get('input_name', None)
    if input_name != "MyKeyword":
        m.save()
    return m    

但如果 input_name 为“MyKeyword”,管理站点仍会创建一个新条目

【问题讨论】:

  • 那段代码有什么问题?您可以将其简化为将条件更改为if input_name != "MyKeyword": super(MyCustomForm, self).save(commit=commit),但除此之外它应该像您编写的那样工作。
  • 我试过了,但错误是:AttributeError 'NoneType' object has no attribute 'save'
  • 那么您的 ModelForm 可能没有返回正在保存的对象:它返回“无”。阅读此答案*.com/a/817364/1688590

标签: python django model django-admin overriding


【解决方案1】:

save() 方法应该返回对象,无论是否保存。它应该看起来像:

def save(self, commit=True):
    input_name = self.cleaned_data.get('input_name')
    if input_name == "MyKeyword":
        commit = False
    return super().save(commit=commit)

但是,如您所见,herehere 已经使用 commit=False 调用了表单,并且稍后通过 ModelAdminsave_model() 方法保存了对象。这就是您获得AttributeError 'NoneType' object has no attribute 'save' 的原因。如果您检查异常的回溯,我很确定错误来自this line

因此,您还应该覆盖 ModelAdminsave_model() 方法:

def save_model(self, request, obj, form, change):
    if form.cleaned_data.get('input_name') == 'MyKeyword':
        return  # Don't save in this case
    super().save_model(request, obj, form, change)

# And you'll also have to override the `ModelAdmin`'s `save_related()` method
# in the same flavor:

def save_related(self, request, form, formsets, change):
    if form.cleaned_data.get('input_name') == 'MyKeyword':
        return  # Don't save in this case
    super().save_related(request, form, formsets, change)

鉴于您对此答案的评论

它现在正在运行,但我只有一个相关问题。管理站点仍然会在顶部显示一个绿色横幅,上面写着“模型已成功添加”。我可以覆盖某些方法,使其显示为红色并显示“模型已存在”吗?

看起来你想要做的不是覆盖保存方法而是controlling form validation。这是完全不同的。您只需覆盖表单的 clean 方法。

from django import forms

def clean(self):
    """
    super().clean()
    if self.cleaned_data.get('input_name') == 'MyKeyword':
        raise forms.ValidationError("The model already exists")

或者,更好,因为看起来你想clean a single field

from django import form

def clean_input_name(self):
    data = self.cleaned_data['input_name']
    if data == 'MyKeyWord':
        raise forms.ValidationError("The model already exists")

但是,我猜input_name 也是您模型的一个字段,您不想只在一个表单上而是在整个项目中引发此错误。在这种情况下,您正在寻找的是Model validators

from django.core.exceptions import ValidationError

def validate_input_name(value):
    if value == 'MyKeyword':
        raise ValidationError("The model already exists")

【讨论】:

  • 它现在正在工作,但我只有一个相关问题。管理站点仍然会在顶部显示一个绿色横幅,上面写着“模型已成功添加”。我可以覆盖某些方法,使其变为红色并显示“模型已存在”吗?
  • 当然可以。但看起来这实际上并不是你想要做的。为什么不从一开始就说要控制表单验证?请参阅what is the XY problem 和我的回答中的更新。另外,当input_name 设置为a 关键字 时,您真的要引发错误吗?还是变量?也许是一个关键字列表?也许是一个从数据库中检索的数据?也许你只是希望这个字段是独一无二? 如果是这样,您为什么要努力隐藏问题的关键信息?