在提交到数据库之前使用 django 清理数据弹出删除数据

Posted

技术标签:

【中文标题】在提交到数据库之前使用 django 清理数据弹出删除数据【英文标题】:using django cleaned data pop to remove data before commit to db 【发布时间】:2015-09-17 00:20:05 【问题描述】:

我有一个带有选择列表的表单。

当用户从award_grant_type选择列表中选择值8888或9999时,我想要一些表单输入字段中可能存在也可能不存在的数据(用户可能已经在表单文本输入中输入了数据字段,然后选择 8888 或 9999)在表单数据提交到数据库之前删除。

所以我有以下model.py代码:

.....
DISPLAY_ONLY_AWARD_AND_GRANT_DESCRIPTION_WITH_PROMPT = 8888
DISPLAY_ONLY_AWARD_AND_GRANT_DESCRIPTION_WITHOUT_PROMPT = 9999
.....

AWARD_GRANT_TYPES = (
    (SELECT_AWARD_AND_GRANT_TYPE, _('Select Type')),
    (AWARD, _('Award')),
    (GRANT, _('Grant')),
    (TRAVEL_GRANT, _('Travel Grant')),
    (OTHER_AWARD, _('Other Award')),
    (OTHER_GRANT, _('Other Grant')),
    (WRITE_MY_OWN_AWARD_AND_GRANT_TYPE_DESCRIPTION, _('Write my own Type description')),  #7777
    (DISPLAY_ONLY_AWARD_AND_GRANT_DESCRIPTION_WITH_PROMPT, _('Display only Description with prompt')),  #8888
    (DISPLAY_ONLY_AWARD_AND_GRANT_DESCRIPTION_WITHOUT_PROMPT, _('Display only Description without prompt')) #9999
)

user = models.ForeignKey(User)
language_version = models.ForeignKey('LanguageVersion')
award_grant_type = models.PositiveIntegerField(choices=AWARD_GRANT_TYPES, default=SELECT_AWARD_AND_GRANT_TYPE, validators=[MinValueValidator(1)])
award_grant_type_description = models.CharField(null=True, blank=True, max_length=250)
award_grant_date = models.DateField(null=True, blank=True)
award_grant_description = models.TextField(null=False, blank=False, max_length=5000)

这是我的 forms.py 干净代码,当用户在提交到数据库之前从选择列表 award_grant_type 中选择了 8888 或 9999 时,应该删除 award_grant_type_descriptionaward_grant_date 字段:

def clean(self):

    cd_agdf = super(AwardGrantDetailsForm, self).clean()

    if 'award_grant_type' in cd_agdf:
        if cd_agdf['award_grant_type'] == '':
            self._errors['award_grant_type'] = self.error_class([_("You must select a Type.")])

        elif cd_agdf['award_grant_type'] == 8888 or cd_agdf['award_grant_type'] == 9999:
            #  remove the entered values when the award grant type only requires minimum data.
            self.cleaned_data.pop('award_grant_type_description', None)
            self.cleaned_data.pop('award_grant_date', None)
        else:
            ....
    return cd_agdf

谁能指出我做错了什么?在表单数据提交到数据库之前,award_grant_type_descriptionaward_grant_date 不会被删除。

编辑/更新

只有在更新现有记录时才会出现此问题。 在将表单保存到数据库之前,新记录会根据需要删除数据。当现有记录有一个日期字段作为数据库记录的一部分并且award_grant_type 从 1 更改为 8888 或 9999 时,award_grant_date 不会从数据库中删除。我不知道为什么。

第二次编辑

我已经发布了一个相关的帖子here。

【问题讨论】:

代码看起来不错。你确定clean 被调用了吗?是否正确评估了相关的 if 语句?我能看到的唯一潜在问题是您从self.cleaned_data 弹出但返回cd_agdf;这些应该都是对同一事物的引用,但可能会更改为始终使用cd_agdf,看看是否有效。 感谢您的回答。我已经进行了更改,但我现在意识到问题只发生在现有记录上 - 请参阅帖子中的编辑/更新。 【参考方案1】:

尝试将self.cleaned_data 更改为cd_agdf。字典,该方法clean 返回,将用作cleaned_data。您从self.cleaned_data 弹出项目,但返回的没有更改cd_ahdf。这在here 中进行了描述(请参阅以“表单的子类...”开头的最后一步)。

【讨论】:

感谢您的回答。我已经进行了更改,但我现在意识到问题只发生在现有记录上 - 请参阅帖子中的编辑/更新。【参考方案2】:

仅回答编辑:关于数据的含义存在争议。

表单验证首先发生,其目的是解析提交的数据,清理并指出数据中的任何错误。此步骤的结果应该是清理后的规范形式的数据。

然后action:如果有效,则执行表单。您解释该数据以采取适当的行动。在这里,将其写入数据库。

您的两个步骤在数据的含义上存在分歧。验证会从最终数据中删除award_grant_type_descriptionaward_grant_date,以表示“删除这些字段”。然后,该操作将丢失的数据解释为 “保留该字段原样”(这是默认的 ModelForm.save() 所做的)。

您的选择:要么遵循ModelForm 的约定并将字段设置为None 而不是删除它们,要么覆盖表单的save(),因此它将丢失的数据解释为“从对象中删除”。除非我有充分的理由更改 ModelForm 的语义,否则我会将字段设置为 None

【讨论】:

【参考方案3】:

我终于解决了这个问题。

当我将值用引号括起来时,问题就解决了。

这是我使用的有效示例代码:

 elif cd_agdf['award_grant_type'] == '8888' or cd_agdf['award_grant_type'] == '9999':

我希望这会对某人有所帮助。

【讨论】:

【参考方案4】:

而不是self.cleaned_data.pop() 执行cd_agdf.pop(),因为您将cd_agdf 分配给superclass

【讨论】:

感谢您的回答。我已经进行了更改,但我现在意识到问题只发生在现有记录上 - 请参阅帖子中的编辑/更新。

以上是关于在提交到数据库之前使用 django 清理数据弹出删除数据的主要内容,如果未能解决你的问题,请参考以下文章

在提交实际表单之前接受弹出窗口中的输入

Django奇怪的SlugField验证,在clean()之前没有引发错误,返回了未清理的数据

django 编辑表单,数据怎么回显呀

在存储数据之前对其进行清理可能意味着存储的数据与用户输入的数据不同 - 这是常见的做法吗?

python测试开发django-121.bootstrap-table弹出模态框修表格数据提交

清理和验证表单php