在我的模型中,我有以下
--- models.py ---
class A(models.Model):
my_Bs = models.ManyToManyField('B', through='AlinksB')
...
class B(models.Model):
...
class AlinksB(models.Model):
my_A = models.ForeignKey(A)
my_B = models.models.ForeignKey(B)
order = models.IntegerField()
相应的管理员也是如此(管理员视图有内联链接B实例,我准备了自定义此内联的formset和表单所需的内容):
--- admin.py ---
class AlinksBInlineForm(forms.ModelForm):
class Meta:
model = AlinksB
class AlinksBInlineFormset(forms.models.BaseInlineFormSet): # there also is a BaseModelFormset
form = AlinksBInlineForm
class AlinksBInline(admin.TabularInline):
formset = AlinksBInlineFormset
model = AlinksB
class AAdmin(admin.ModelAdmin):
form = AForm
inlines = (AlinksBInline,)
...
class BAdmin(admin.ModelAdmin):
...
现在要自定义表单验证,没什么困难:只需覆盖表单对象的“clean”方法。如果你想在formset中有许多不同的表单,我认为你只需要在formset的“ init ”方法中手动更改一些。但是,当我们清理formset时,以编程方式验证所有表单,以及仅在某些条件下才会这样做。
在我的情况下:如果所有订单(要排除的内联行)都为空,如何使用自动增量自动设置“订单”字段(在管理员视图的内联中)?!
答案 0 :(得分:3)
我花了很多时间用Google搜索在Django Framework中进行表单集验证时尝试执行自动表单清理。几天之后,我无法找到解决方案,所以我开始关注Django的源代码,看看工作领域,小部件,表单和表单集。
以下是我的理解:
- 用户在提交存储在formset的“数据”属性中的formset时发布的所有数据。此属性非常难看,无法直接使用。 - 表单只是字段的包装器(它调用所有字段的干净方法并填充错误缓冲区,只有几个)
- 表单字段包含一个小部件。此窗口小部件允许从formset的“data”属性中返回字段的原始值
form.add_prefix('field name') # returns the 'field prefix', the key of formset.data used to retrieve the field's raw value
form.fields['field name'].widget.value_from_datadict(form.data, form.files, 'field prefix') # returns the raw value
- 表单字段还有一个方法可以将原始值转换为正确的python值(在我的例子中:order是一个整数,如果字段为空则为None)
form.fields['field name'].to_python(raw_value) # returns a value with the right type
- 您可以使用以下代码
更改formset中某个字段的值form.data.__setitem__('field prefix', value) # code to update an iterable knowing the key to change
- 一旦修改了字段值,您可以调用表单的“ full_clean ”方法重试清除它们(这将删除以前的错误)。
- 一旦您再次验证了表单,您也可以使用“ full_clean ”方法重试验证表单集。但要注意避免无限循环
- 表单干净数据只能使用只读数据,在表单或formset中添加更多错误消息
另一种解决方案是手动更改“form.clean_data”属性,并清除formset.errors和所有form.errors
希望它可以帮助处理与我相同情况的人!
Ricola3D