Django FormWizard - 如何根据上一步动态创建表单集
Posted
技术标签:
【中文标题】Django FormWizard - 如何根据上一步动态创建表单集【英文标题】:Django FormWizard - How do you dynamically create a formset based on previous step 【发布时间】:2011-12-31 15:00:38 【问题描述】:我看过this 的帖子,但它不起作用(部分原因是它已经过时了)。我还研究了源代码树但无济于事(测试有所帮助),但我找不到答案。我要做的是在form0('start')中获取一组种子数据,它将为step2动态构建一个formset。第 2 步只是一个验证步骤。
-
'start' - 用户输入细分 (subA)、邮政编码 (12345) 和批次的 csv (51,52,53)
'step2' - 创建一个动态表单(modelformset),其中 3 个表单分别代表 51,52,53
用户点击,模型构建完成
即
data = [ 'subdivision': <subA>, 'zipcode': '12345', 'lot_number': '51'
'subdivision': <subA>, 'zipcode': '12345', 'lot_number': '52'
'subdivision': <subA>, 'zipcode': '12345', 'lot_number': '53' ]
我的尝试
在实施解决方案here 时,我只得到data=None
。这是过时的,并且查看源代码我认为“正确”的方法是简单地覆盖get_form_instance
方法并提供它get_cleaned_data_for_step
,但这似乎重新验证并做了很多比我认为它需要的更多的东西(而且它没有工作)。
所以.. 我正在寻找的是两件事。
-
获取以前的表单数据的正确方法是什么。
如何获取这些数据并使用它来创建 n 个表单集。
FWIW 我正在使用 Django 1.4-alpha formset 向导。
这就是我所拥有的。
# urls.py
url(r'homes/bulk/$', TestWizard.as_view([('start', BulkHomeForm0),
('step2', HomeFormSet)])),
# Models.py
class Subdivision(models.Model):
name = models.CharField(max_length=64)
class Home(models.Model):
lot_number = models.CharField(max_length=16)
subdivision = models.ForeignKey(Subdivision)
zipcode = models.IntegerField(validators=[validate_zipcode], null=True)
# Forms
class BulkHomeForm0(forms.Form):
subdivision = forms.ModelChoiceField(queryset=Subdivision.objects.all(), required=True)
zipcode = USZipCodeField(required=True)
lots = forms.CharField(max_length=5000, widget=forms.Textarea()
def clean(self):
subdivision = self.cleaned_data.get('subdivision', False)
zipcode = self.cleaned_data.get('zipcode', False)
final_data = []
for item in self.cleaned_data.get('lots', "").split(",")
final_data.append('subdivision':subdivision,
'zipcode':zipcode,
'lot_number':item)
self.cleaned_data['homes'] = final_data
class BulkHomeForm1(forms.ModelForm):
class Meta:
model = Home
HomeFormSet = modelformset_factory(Home, form=BulkHomeForm1, extra=2)
# Views.py
class TestWizard(WizardView):
storage_name = 'django.contrib.formtools.wizard.storage.session.SessionStorage'
def get_form(self, step=None, data=None, files=None):
form = super(TestWizard, self).get_form(step=step, data=data, files=files)
return form
def done(self, form_list, **kwargs):
return render_to_response('done.html',
'form_data': [form.cleaned_data for form in form_list],
)
【问题讨论】:
【参考方案1】:这是我想出的..
我似乎无法让 modelForm 很好地工作,所以我将两者分开并将它们合并到 done
。它还不完美,但它正在接近..
class BulkHomeForm1(forms.Form):
lot_number = forms.CharField(max_length=16, required=True)
street_line1 = forms.CharField(max_length=100, required=True)
floorplan = forms.ModelChoiceField(queryset=Floorplan.objects.filter(is_active=True), required=False)
start_date = forms.DateField(required=False)
temp_storage_location = tempfile.mkdtemp(dir=settings.MEDIA_ROOT, prefix="bulk_homes_")
os.chmod(temp_storage_location, 02775) # TODO FIX ME
temp_storage = FileSystemStorage(location=temp_storage_location)
class BulkHomeWizard(SessionWizardView):
file_storage = temp_storage
def get_form(self, step=None, data=None, files=None):
form = super(BulkHomeWizard, self).get_form(step=step, data=data, files=files)
if self.steps.current == 'start' and form.prefix != "step2":
# Limit the subdivisions down to the specifics
sub_qs = Subdivision.objects.filter(is_active=True)
if self.request.user.company_type == "rater":
sub_qs = sub_qs.filter(rater_orgs=self.request.user.company.id)
elif self.request.user.company_type == "eep":
sub_qs = sub_qs.filter(eep_orgs=self.request.user.company.id)
form.fields['subdivision'].queryset = sub_qs
return form
def get_context_data(self, form, **kwargs):
context = super(BulkHomeWizard, self).get_context_data(form, **kwargs)
self.template_name = 'axis/bulk_%s.html' % self.steps.current
return context
def get_form_initial(self, step):
"""This is used to seed the model set with information from the previous step"""
if step == 'step2':
log.info("Into Step 2")
data = self.get_cleaned_data_for_step('start')['homes']
return data
return self.initial_dict.get(step, )
def done(self, form_list, **kwargs):
cleaned_data = [form.cleaned_data for form in form_list]
subdivision = cleaned_data[0].get('subdivision')
city = subdivision.city
state = subdivision.state
zipcode = cleaned_data[0].get('zipcode')
for form in cleaned_data[1]:
data = Home.objects.get_or_create(lot_number = form.get('lot_number'),
floorplan = form.get('floorplan', None),
street_line1 = form.get('street_line1', None),
subdivision = subdivision,
city = subdivision.city, state=subdivision.state,
zipcode=zipcode,
start_date = form.get('start_date', None),)
obj, created = data
obj.clean()
obj.save()
if created:
log.info("Create new Home")
return HttpResponseRedirect(reverse("subdivision_view", kwargs='subdivision_id': subdivision.id))
【讨论】:
以上是关于Django FormWizard - 如何根据上一步动态创建表单集的主要内容,如果未能解决你的问题,请参考以下文章
Django:如何使用 ModelFormSet 和 FormWizard 过滤 ForeignKey 选择(例如使用 request.user)?
Django FormWizard如何动态更改form_list
django manytomany 字段使用 through 和 formwizard