我有一个要呈现为嵌套表单集的 3 级测试模型。每个测试有多个结果,每个结果可以有多个行。我正在关注Yergler 的创建嵌套表单集的方法,以及更新 Yergler 代码以获取最新 Django 版本的SO question(我在 1.4 上)
我遇到了麻烦,因为我想使用 FormSet 的“额外”参数在表单集中包含一个额外的 Line。每个 Line 的 ForeignKey 必须指向 Line 所属的 Result,但用户不能更改,所以我使用 HiddenInput 字段将 Result 包含在 FormSet 的每个 Lines 中。
这会导致“缺少必填字段”验证错误,因为该result
字段总是被填写(在 add_fields 中),但text
可能severity
不会(如果用户选择不输入另一行)。我不知道处理这种情况的正确方法。我认为我不需要result
在 add_fields 中包含初始值,并且必须有更好的方法可以实际工作。
在下面更新到这个问题的底部
如有必要,我很乐意添加更多细节。
我的自定义表单集的代码:
LineFormSet = modelformset_factory(
Line,
form=LineForm,
formset=BaseLineFormSet,
extra=1)
class BaseResultFormSet(BaseInlineFormSet):
def __init__(self, *args, **kwargs):
super(BaseResultFormSet, self).__init__(*args, **kwargs)
def is_valid(self):
result = super(BaseResultFormSet, self).is_valid()
for form in self.forms:
if hasattr(form, 'nested'):
for n in form.nested:
n.data = form.data
if form.is_bound:
n.is_bound = True
for nform in n:
nform.data = form.data
if form.is_bound:
nform.is_bound = True
# make sure each nested formset is valid as well
result = result and n.is_valid()
return result
def save_all(self, commit=True):
objects = self.save(commit=False)
if commit:
for o in objects:
o.save()
if not commit:
self.save_m2m()
for form in set(self.initial_forms + self.saved_forms):
for nested in form.nested:
nested.save(commit=commit)
def add_fields(self, form, index):
# Call super's first
super(BaseResultFormSet, self).add_fields(form, index)
try:
instance = self.get_queryset()[index]
pk_value = instance.pk
except IndexError:
instance=None
pk_value = hash(form.prefix)
q = Line.objects.filter(result=pk_value)
form.nested = [
LineFormSet(
queryset = q, #data=self.data, instance = instance, prefix = 'LINES_%s' % pk_value)]
prefix = 'lines-%s' % pk_value,
initial = [
{'result': instance,}
]
)]
测试模型
class Test(models.Model):
id = models.AutoField(primary_key=True, blank=False, null=False)
attempt = models.ForeignKey(Attempt, blank=False, null=False)
alarm = models.ForeignKey(Alarm, blank=False, null=False)
trigger = models.CharField(max_length=64)
tested = models.BooleanField(blank=False, default=True)
结果模型
class Result(models.Model):
id = models.AutoField(primary_key=True)
test = models.ForeignKey(Test)
location = models.CharField(max_length=16, choices=locations)
was_audible = models.CharField('Audible?', max_length=8, choices=audible, default=None, blank=True)
线型
class Line(models.Model):
id = models.AutoField(primary_key=True)
result = models.ForeignKey(Result, blank=False, null=False)
text = models.CharField(max_length=64)
severity = models.CharField(max_length=4, choices=severities, default=None)
更新
昨晚我将此添加到我的 LineForm(ModelForm) 类中:
def save(self, commit=True):
saved_instance = None
if not(len(self.changed_data) == 1 and 'result' in self.changed_data):
saved_instance = super(LineForm, self).save(commit=commit)
return saved_instance
如果仅填写结果(隐藏输入),它会忽略保存请求。这种方法我还没有遇到任何问题,但我还没有尝试添加新表单。