Django 复合/嵌套/子表单?

发布于 09-06 15:06 字数 254 浏览 14 评论 0原文

我正在寻找这些 Django SuperForms 的更新版本。似乎无法让它在 Django 1.2 中工作。特别是,我希望它能够与 ModelForms 一起使用。

我的用例几乎与他的相同;我有一个 Address 模型,我想在各个地方将其用作子表单。尝试将视图函数中的所有内容组合起来是一件痛苦的事情。

I'm looking for an updated version of these Django SuperForms. Can't seem to get it to work in Django 1.2. In particular, I'd like it to work with ModelForms.

My use case is almost identical to his; I have an Address model that I'd like to use as a sub-form in various places. It's a pain to try and combine everything in the view func.

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

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

发布评论

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

评论(1

大姐,你呐2024-09-13 15:06:50

我已更新 superforms.py 以使用 1.2,并将其附加到您链接到的票证中: http://code.djangoproject.com/attachment/ticket/3706/superform.2.py

我正在从事的一个项目可以从中受益,所以我想我'我也会花时间帮助你。

请记住,我只是让它在 1.2 中工作,并没有真正尝试清理内部结构。现在我已经有了证明 API 的测试用例,我可以稍后返回并清理它。

如果您将其与 ModelForms 一起使用并且您想要 save() 功能,则必须重写 SuperForm 类上的方法。

我目前在我的“公共”存储库中本地拥有它,代码覆盖率约为 90%,涵盖多个子表单、混合子表单和子表单。声明的表单和模型表单。我已经包含了下面的测试用例(注意它使用我的 TestCaseBase 类,但这应该可以让您了解 API 的要点)。如果您有任何疑问或我遗漏的任何领域,请告诉我。

from django_common.forms.superform import SuperForm, SubForm
from django_common.test import TestCaseBase
from django import forms

class WhenSuperFormsIsUsedWithOnlySubForms(TestCaseBase):
    def get_superform_with_forms(self, post_data=None):
        class AddressForm(forms.Form):
            street = forms.CharField(max_length=255)
            city = forms.CharField(max_length=255)

        class BusinessLocationForm(forms.Form):
            phone_num = forms.CharField(max_length=255)

        class TestSuperForm(SuperForm):
            address = SubForm(AddressForm)
            business_location = SubForm(BusinessLocationForm)

        return TestSuperForm(data=post_data)

    def should_not_be_valid_with_no_data(self):
        tsf = self.get_superform_with_forms()
        self.assert_false(tsf.is_valid())

    def should_have_two_sub_forms(self):
        tsf = self.get_superform_with_forms()
        self.assert_equal(len(tsf.base_subforms),  2)
        self.assert_equal(len(tsf.forms), 2)

    def should_display_as_ul(self):
        tsf = self.get_superform_with_forms()
        self.assert_equal(tsf.as_ul(), '<li><label for="id_business_location-phone_num">Phone num:</label> <input id="id_business_location-phone_num" type="text" name="business_location-phone_num" maxlength="255" /></li>\n<li><label for="id_address-street">Street:</label> <input id="id_address-street" type="text" name="address-street" maxlength="255" /></li>\n<li><label for="id_address-city">City:</label> <input id="id_address-city" type="text" name="address-city" maxlength="255" /></li>')

    def should_display_as_table(self):
        tsf = self.get_superform_with_forms()
        self.assert_equal(tsf.as_table(), '<tr><th><label for="id_business_location-phone_num">Phone num:</label></th><td><input id="id_business_location-phone_num" type="text" name="business_location-phone_num" maxlength="255" /></td></tr>\n<tr><th><label for="id_address-street">Street:</label></th><td><input id="id_address-street" type="text" name="address-street" maxlength="255" /></td></tr>\n<tr><th><label for="id_address-city">City:</label></th><td><input id="id_address-city" type="text" name="address-city" maxlength="255" /></td></tr>')

    def should_display_as_p(self):
        tsf = self.get_superform_with_forms()
        self.assert_equal(tsf.as_p(), '<p><label for="id_business_location-phone_num">Phone num:</label> <input id="id_business_location-phone_num" type="text" name="business_location-phone_num" maxlength="255" /></p>\n<p><label for="id_address-street">Street:</label> <input id="id_address-street" type="text" name="address-street" maxlength="255" /></p>\n<p><label for="id_address-city">City:</label> <input id="id_address-city" type="text" name="address-city" maxlength="255" /></p>')

    def should_display_as_table_with_unicode(self):
        tsf = self.get_superform_with_forms()
        self.assert_equal(tsf.__unicode__(), tsf.as_table())

    def should_be_valid_if_good_data(self):
        data = {
            'business_location-phone_num' : '8055551234',
            'address-street' : '1234 Street Dr.',
            'address-city' : 'Santa Barbara',
        }
        tsf = self.get_superform_with_forms(data)
        self.assert_true(tsf.is_valid())
        self.assert_equal(tsf.cleaned_data['business_location']['phone_num'],
                          '8055551234')
        self.assert_equal(tsf.cleaned_data['address']['street'], '1234 Street Dr.')
        self.assert_equal(tsf.cleaned_data['address']['city'], 'Santa Barbara')

    def should_be_invalid_if_missing_data(self):
        data = {
            'business_location-phone_num' : '8055551234',
            'address-street' : '1234 Street Dr.',
        }
        tsf = self.get_superform_with_forms(data)
        self.assert_false(tsf.is_valid())

        self.assert_false(tsf.errors['business_location'])
        self.assert_true(tsf.errors['address'])
        self.assert_equal(tsf.errors['address']['city'], ['This field is required.'])

    def should_be_invalid_if_invalid_data(self):
        data = {
            'business_location-phone_num' : '8055551234',
            'address-street' : '1234 Street Dr.',
            'address-city' : '',
        }
        tsf = self.get_superform_with_forms(data)
        self.assert_false(tsf.is_valid())


class WhenSuperformsIsUsedWithSubFormsAndDeclaredFields(TestCaseBase):
    """Some basic sanity checks that working with fields combined with SubForms works."""
    def get_superform_with_forms(self, post_data=None):
        class AddressForm(forms.Form):
            street = forms.CharField(max_length=255)

        class TestSuperForm(SuperForm):
            name = forms.CharField(max_length=255)
            address = SubForm(AddressForm)

        return TestSuperForm(data=post_data)

    def should_not_be_valid_with_no_data(self):
        tsf = self.get_superform_with_forms()
        self.assert_false(tsf.is_valid())

    def should_have_two_forms_and_a_single_subform(self):
        tsf = self.get_superform_with_forms()
        self.assert_equal(len(tsf.base_subforms),  1)
        self.assert_equal(len(tsf.forms), 2)

    def should_print_as_table(self):
        tsf = self.get_superform_with_forms()
        self.assert_equal(tsf.as_table(), '<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" maxlength="255" /></td></tr>\n<tr><th><label for="id_address-street">Street:</label></th><td><input id="id_address-street" type="text" name="address-street" maxlength="255" /></td></tr>')

    def should_validate_when_fields_exist(self):
        data = {
            'name': 'Sam',
            'address-street': 'Some Street',
        }
        tsf = self.get_superform_with_forms(data)
        self.assert_true(tsf.is_valid())

        self.assert_equal(tsf.cleaned_data['name'], 'Sam')
        self.assert_equal(tsf.cleaned_data['address']['street'], 'Some Street')

    def should_not_validate_with_invalid_data(self):
        data = {
            'name': '',
            'address-street': 'Some Street',
        }
        tsf = self.get_superform_with_forms(data)
        self.assert_false(tsf.is_valid())

        self.assert_equal(tsf.errors['name'], ['This field is required.'])



class WhenSuperformsIsUsedWithModelForms(TestCaseBase):
    def get_superform_with_forms(self, post_data=None):
        from django.db import models
        class Address(models.Model):
            city = models.CharField(max_length=255)

        class AddressForm(forms.ModelForm):
            class Meta:
                model = Address

        class TestSuperForm(SuperForm):
            address = SubForm(AddressForm)

        return TestSuperForm(data=post_data)

    def should_not_be_valid_with_no_data(self):
        tsf = self.get_superform_with_forms()
        self.assert_false(tsf.is_valid())

    def should_have_two_forms_and_a_single_subform(self):
        tsf = self.get_superform_with_forms()
        self.assert_equal(len(tsf.base_subforms),  1)
        self.assert_equal(len(tsf.forms), 1)

    def should_print_as_table(self):
        tsf = self.get_superform_with_forms()
        self.assert_equal(tsf.as_table(), '<tr><th><label for="id_address-city">City:</label></th><td><input id="id_address-city" type="text" name="address-city" maxlength="255" /></td></tr>')

    def should_validate_when_fields_exist(self):
        data = {
            'address-city': 'Some City',
        }
        tsf = self.get_superform_with_forms(data)
        self.assert_true(tsf.is_valid())

        self.assert_equal(tsf.cleaned_data['address']['city'], 'Some City')

    def should_not_validate_with_invalid_data(self):
        data = {
            'address-city': '',
        }
        tsf = self.get_superform_with_forms(data)
        self.assert_false(tsf.is_valid())

        self.assert_equal(tsf.errors['address']['city'], ['This field is required.'])

享受吧!

I've updated superforms.py to work w/1.2, and attached it to the ticket you linked to: http://code.djangoproject.com/attachment/ticket/3706/superform.2.py

There's a project I'm working on that could benefit from this, so I figured I'd spend the time and help you out as well.

Keep in mind that I just got this to work w/1.2, and didn't really try to clean up the internals. Now that I have test cases proving the API, I can go back and clean that up later.

If you're using it with ModelForms and you'd like the save() functionality you'll have to override the method on your SuperForm class.

I currently have it locally in my "common" repository w/~90% code coverage that covers multiple SubForms, mixed SubForms & declared forms, and ModelForms. I've included the test cases below (beware it uses my TestCaseBase class, but this should give you the gist of the API). Let me know if you have questions, or any areas I missed.

from django_common.forms.superform import SuperForm, SubForm
from django_common.test import TestCaseBase
from django import forms

class WhenSuperFormsIsUsedWithOnlySubForms(TestCaseBase):
    def get_superform_with_forms(self, post_data=None):
        class AddressForm(forms.Form):
            street = forms.CharField(max_length=255)
            city = forms.CharField(max_length=255)

        class BusinessLocationForm(forms.Form):
            phone_num = forms.CharField(max_length=255)

        class TestSuperForm(SuperForm):
            address = SubForm(AddressForm)
            business_location = SubForm(BusinessLocationForm)

        return TestSuperForm(data=post_data)

    def should_not_be_valid_with_no_data(self):
        tsf = self.get_superform_with_forms()
        self.assert_false(tsf.is_valid())

    def should_have_two_sub_forms(self):
        tsf = self.get_superform_with_forms()
        self.assert_equal(len(tsf.base_subforms),  2)
        self.assert_equal(len(tsf.forms), 2)

    def should_display_as_ul(self):
        tsf = self.get_superform_with_forms()
        self.assert_equal(tsf.as_ul(), '<li><label for="id_business_location-phone_num">Phone num:</label> <input id="id_business_location-phone_num" type="text" name="business_location-phone_num" maxlength="255" /></li>\n<li><label for="id_address-street">Street:</label> <input id="id_address-street" type="text" name="address-street" maxlength="255" /></li>\n<li><label for="id_address-city">City:</label> <input id="id_address-city" type="text" name="address-city" maxlength="255" /></li>')

    def should_display_as_table(self):
        tsf = self.get_superform_with_forms()
        self.assert_equal(tsf.as_table(), '<tr><th><label for="id_business_location-phone_num">Phone num:</label></th><td><input id="id_business_location-phone_num" type="text" name="business_location-phone_num" maxlength="255" /></td></tr>\n<tr><th><label for="id_address-street">Street:</label></th><td><input id="id_address-street" type="text" name="address-street" maxlength="255" /></td></tr>\n<tr><th><label for="id_address-city">City:</label></th><td><input id="id_address-city" type="text" name="address-city" maxlength="255" /></td></tr>')

    def should_display_as_p(self):
        tsf = self.get_superform_with_forms()
        self.assert_equal(tsf.as_p(), '<p><label for="id_business_location-phone_num">Phone num:</label> <input id="id_business_location-phone_num" type="text" name="business_location-phone_num" maxlength="255" /></p>\n<p><label for="id_address-street">Street:</label> <input id="id_address-street" type="text" name="address-street" maxlength="255" /></p>\n<p><label for="id_address-city">City:</label> <input id="id_address-city" type="text" name="address-city" maxlength="255" /></p>')

    def should_display_as_table_with_unicode(self):
        tsf = self.get_superform_with_forms()
        self.assert_equal(tsf.__unicode__(), tsf.as_table())

    def should_be_valid_if_good_data(self):
        data = {
            'business_location-phone_num' : '8055551234',
            'address-street' : '1234 Street Dr.',
            'address-city' : 'Santa Barbara',
        }
        tsf = self.get_superform_with_forms(data)
        self.assert_true(tsf.is_valid())
        self.assert_equal(tsf.cleaned_data['business_location']['phone_num'],
                          '8055551234')
        self.assert_equal(tsf.cleaned_data['address']['street'], '1234 Street Dr.')
        self.assert_equal(tsf.cleaned_data['address']['city'], 'Santa Barbara')

    def should_be_invalid_if_missing_data(self):
        data = {
            'business_location-phone_num' : '8055551234',
            'address-street' : '1234 Street Dr.',
        }
        tsf = self.get_superform_with_forms(data)
        self.assert_false(tsf.is_valid())

        self.assert_false(tsf.errors['business_location'])
        self.assert_true(tsf.errors['address'])
        self.assert_equal(tsf.errors['address']['city'], ['This field is required.'])

    def should_be_invalid_if_invalid_data(self):
        data = {
            'business_location-phone_num' : '8055551234',
            'address-street' : '1234 Street Dr.',
            'address-city' : '',
        }
        tsf = self.get_superform_with_forms(data)
        self.assert_false(tsf.is_valid())


class WhenSuperformsIsUsedWithSubFormsAndDeclaredFields(TestCaseBase):
    """Some basic sanity checks that working with fields combined with SubForms works."""
    def get_superform_with_forms(self, post_data=None):
        class AddressForm(forms.Form):
            street = forms.CharField(max_length=255)

        class TestSuperForm(SuperForm):
            name = forms.CharField(max_length=255)
            address = SubForm(AddressForm)

        return TestSuperForm(data=post_data)

    def should_not_be_valid_with_no_data(self):
        tsf = self.get_superform_with_forms()
        self.assert_false(tsf.is_valid())

    def should_have_two_forms_and_a_single_subform(self):
        tsf = self.get_superform_with_forms()
        self.assert_equal(len(tsf.base_subforms),  1)
        self.assert_equal(len(tsf.forms), 2)

    def should_print_as_table(self):
        tsf = self.get_superform_with_forms()
        self.assert_equal(tsf.as_table(), '<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" maxlength="255" /></td></tr>\n<tr><th><label for="id_address-street">Street:</label></th><td><input id="id_address-street" type="text" name="address-street" maxlength="255" /></td></tr>')

    def should_validate_when_fields_exist(self):
        data = {
            'name': 'Sam',
            'address-street': 'Some Street',
        }
        tsf = self.get_superform_with_forms(data)
        self.assert_true(tsf.is_valid())

        self.assert_equal(tsf.cleaned_data['name'], 'Sam')
        self.assert_equal(tsf.cleaned_data['address']['street'], 'Some Street')

    def should_not_validate_with_invalid_data(self):
        data = {
            'name': '',
            'address-street': 'Some Street',
        }
        tsf = self.get_superform_with_forms(data)
        self.assert_false(tsf.is_valid())

        self.assert_equal(tsf.errors['name'], ['This field is required.'])



class WhenSuperformsIsUsedWithModelForms(TestCaseBase):
    def get_superform_with_forms(self, post_data=None):
        from django.db import models
        class Address(models.Model):
            city = models.CharField(max_length=255)

        class AddressForm(forms.ModelForm):
            class Meta:
                model = Address

        class TestSuperForm(SuperForm):
            address = SubForm(AddressForm)

        return TestSuperForm(data=post_data)

    def should_not_be_valid_with_no_data(self):
        tsf = self.get_superform_with_forms()
        self.assert_false(tsf.is_valid())

    def should_have_two_forms_and_a_single_subform(self):
        tsf = self.get_superform_with_forms()
        self.assert_equal(len(tsf.base_subforms),  1)
        self.assert_equal(len(tsf.forms), 1)

    def should_print_as_table(self):
        tsf = self.get_superform_with_forms()
        self.assert_equal(tsf.as_table(), '<tr><th><label for="id_address-city">City:</label></th><td><input id="id_address-city" type="text" name="address-city" maxlength="255" /></td></tr>')

    def should_validate_when_fields_exist(self):
        data = {
            'address-city': 'Some City',
        }
        tsf = self.get_superform_with_forms(data)
        self.assert_true(tsf.is_valid())

        self.assert_equal(tsf.cleaned_data['address']['city'], 'Some City')

    def should_not_validate_with_invalid_data(self):
        data = {
            'address-city': '',
        }
        tsf = self.get_superform_with_forms(data)
        self.assert_false(tsf.is_valid())

        self.assert_equal(tsf.errors['address']['city'], ['This field is required.'])

Enjoy!

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