Django FormWizard - 如何根据上一步动态创建表单集

发布于 2024-12-16 14:16:33 字数 2989 浏览 2 评论 0原文

我见过 这篇文章 并不起作用(部分原因是它已过时)。我还研究了源代码树,但无济于事(测试有帮助),但我找不到答案。我想要做的是在 form0 ('start')中获取一组数据种子,它将动态地为步骤 2 构建一个表单集。步骤 2 只是一个验证步骤。

  1. 'start' - 用户输入分区 (subA)、邮政编码 (12345) 和批次 csv (51,52,53)
  2. 'step2' - 创建动态表单 (modelformset),其中包含代表 51,52,53
  3. 用户点击 的 3 个表单go 并构建模型

,即

data = [ { 'subdivision': <subA>, 'zipcode': '12345', 'lot_number': '51'}
         { 'subdivision': <subA>, 'zipcode': '12345', 'lot_number': '52'}
         { 'subdivision': <subA>, 'zipcode': '12345', 'lot_number': '53'} ]

我尝试过的内容

实施解决方案时这里我只获取data=None。这是过时的,查看源代码,我认为“正确”的方法是简单地重写 get_form_instance 方法并提供它get_cleaned_data_for_step,但这似乎重新验证和做了比我认为需要做的更多的事情(但它不起作用)。

所以..我正在寻找两件事。

  1. 获取以前的表单数据的正确方法是什么?
  2. 我如何获取该数据并使用它来创建 n 个表单集。

FWIW 我正在使用 Django 1.4-alpha 表单集向导。

这是我所拥有的。

# 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],
        })

I've seen this post and it's not working (in part because it's dated). I've also studied the source tree to no avail (the tests helped) but I can't find my answer. What I'm looking to do is get a seed set of data in form0 ('start') which will dynamically build a formset for step2. Step 2 is simply a verification step.

  1. 'start' - User enters subdivision (subA), zipcode (12345) and a csv of lots (51,52,53)
  2. 'step2' - A dynamic form (modelformset) is created with 3 forms representing 51,52,53
  3. User hits go and the models are built

i.e.

data = [ { 'subdivision': <subA>, 'zipcode': '12345', 'lot_number': '51'}
         { 'subdivision': <subA>, 'zipcode': '12345', 'lot_number': '52'}
         { 'subdivision': <subA>, 'zipcode': '12345', 'lot_number': '53'} ]

What I've tried

When implementing the solution here I only get data=None. This is dated and looking through the source I thought the "right" way to do this was to simply override the get_form_instance method and feed itget_cleaned_data_for_step, but that appears to revalidate and do a lot more stuff than what I think it needs to (and it didn't work).

So.. What I'm looking for is two things.

  1. What is the right way to get the previous forms data.
  2. How do I take that data and use it to create a n-number of formsets.

FWIW I am using Django 1.4-alpha formset wizard.

Here is what I have.

# 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],
        })

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

恍梦境° 2024-12-23 14:16:33

这是我想到的......

我似乎无法让 modelForm 很好地工作,所以我将两者分开并在完成时将它们合并。它还不完美,但已经很接近了..

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}))

Here is what I came up with..

I couldn't seem to get a modelForm to work nicely so I kept the two separate and merged them at done. It isn't perfect yet but it's getting close..

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}))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文