django 忽略表单集中更改的字段

问题描述 投票:0回答:3

我有以下型号:

class Recipe(models.Model):
    fields...

class Ingredient(models.Model):
    fields...

class UsesIngredient(models.Model):
    recipe = models.ForeignKey(Recipe)
    ingredient = models.ForeignKey(Ingredient)
    amount = models.FloatField()
    group = models.CharField()

我有一个视图,允许用户通过动态表单集为特定配方添加任意数量的“UsesIngredient”模型。组属性会自动填充,对用户隐藏。

问题是,当用户在表单集中添加新表单但未填写任何字段时,我不希望保存该表单。然而,django 仍然尝试保存表单,因为“group”属性已“更改”(因为在创建额外表单时已自动填写)。

有什么办法可以解决这个问题吗?

谢谢!

python django django-forms inline-formset
3个回答
2
投票

嗯,我对蒂姆·埃德加的解决方案仍然不太满意,所以我继续寻找。我想我找到了我要找的东西。 “Form”类有两个未记录的方法可在本例中使用:“has_changed()”和“_get_changed_data”。

在 ModelFormSet 验证期间,每个表单都会检查“has_changed()”。如果表单未更改,则跳过验证并假定表单正确。 同样,在 ModelFormSet 保存期间,save_new_objects 检查每个表单以查看其是否已更改。如果没有更改,则不会保存表单。

所以我的解决方案是重写 has_changed() 方法,如果只有 'group' 属性发生了更改,并且所有其他字段都为空,则返回 False。这是我的实现:

class UsesIngredientForm(forms.ModelForm):    
    class Meta:
        model = UsesIngredient

    def has_changed(self, *args, **kwargs):
        self._get_changed_data(*args, **kwargs)
        # If group is in changed_data, but no other fields are filled in, remove group so
        # the form will not be validated or saved
        if 'group' in self._changed_data and len(self._changed_data) == 1:
            contains_data = False
            for name in ['ingredient', 'amount', 'unit']:
                field = self.fields[name]
                prefixed_name = self.add_prefix(name)
                data_value = field.widget.value_from_datadict(self.data, self.files, prefixed_name)
                if data_value:
                    contains_data = True
                    break
            if not contains_data:
                self._changed_data.remove('group')
        return bool(self._changed_data)

希望这对将来的任何人有帮助!

编辑: 我编辑了这个答案以反映蒂姆·埃德加的评论。 我意识到这个实现仍然使用“私有”方法,但我还没有找到仅使用公开记录的方法的更干净的实现。但也许这只是我自己的无能:)。


0
投票

您可以尝试通过设置

blank=False
使所有字段都需要一个值。查看更多这里。应该需要验证您关心的值不留空。

如果这不起作用,您可以尝试创建自己的自定义

save
方法来执行您关心的验证。

def save(self, *args, **kwargs):
   # Do your checks on the properties such as self.group, self.amount, etc
   # If it is fine then call
   super(UsesIngredient, self).save(*args, **kwargs)

0
投票

自从问题被提出并回答以来,django 更改为包含公共 和记录的方法

changed_data
,这有助于实施 与 Gargamel 建议的解决方案类似。

例如:

class UsesIngredientForm(forms.ModelForm):    
    class Meta:
        model = UsesIngredient

    def has_changed(self):
        """
        Checks if only the "group" field has changed data. If so, returns `False`,
        indicating no data of relevance has changed. This avoids triggering validation
        if only the "group" value changed from its initial state. 
        """
        changed_data = self.changed_data

        if len(changed_data) == 1 and changed_data[0] == "group":
            return False
        
        return super().has_changed()

changed_data
属性记录在此处:https://docs.djangoproject.com/en/5.0/ref/forms/api/#django.forms.Form.changed_data

changed_data 属性返回字段名称的列表,这些字段的值在表单的绑定数据(通常是 request.POST)中与初始中提供的值不同。如果没有数据不同,它将返回一个空列表。

© www.soinside.com 2019 - 2024. All rights reserved.