获取 Django 应用程序中的所有表单对象

Get all form objects in a Django application

这是我想要做的:

  1. 检索我所有继承自 forma.Form
  2. 的所有 Django 应用程序中的所有对象的列表
  3. 查找所有在表单上定义的 CharField
  4. 验证每个字段都指定了 max_length kwarg

我的目标是编写单元测试,如果我们的系统中存在未指定最大长度的表单,则该测试失败。

我该怎么做?

我找到了一种使用反射样式代码来检索从 models.Form class 继承的所有对象的方法,请参见下面的测试:

class TestAllFormsMeetBasicBoundaryTests(TestCase):
    def all_subclasses(self, cls):
        return cls.__subclasses__() + [g for s in cls.__subclasses__()
                                   for g in self.all_subclasses(s)]

    # this is teh awesome-sause! dynamically finding objects in the project FTW!
    def test_all_char_fields_contain_max_length_value(self):
        from django.apps import apps
        import django.forms
        import importlib
        log.info('loading all forms modules from apps')
        at_least_one_module_found = False
        for app_name in settings.PROJECT_APPS: #this is a list of in project apps
            app = apps.get_app_config(app_name)
            try:
                importlib.import_module('{0}.forms'.format(app.label))
                log.info('forms loaded from {0}'.format(app.label))
                at_least_one_module_found = True
            except ImportError as e:
                pass
        self.assertTrue(at_least_one_module_found, 'No forms modules were found in any of the apps. this should never be true!')
        all_forms = self.all_subclasses(django.forms.Form)

        messages = []
        for form in all_forms:
            for key in form.declared_fields.keys():
                field = form.declared_fields[key]
                if isinstance(field, django.forms.CharField) and form.__module__.partition('.')[0] in settings.PROJECT_APPS and field.max_length is None:
                    messages.append('{0}.{1}.{2} is missing a max_length value.'.format(form.__module__, form.__name__, key))
            pass

        self.assertEquals(0, len(messages),
                          'CharFields must always have a max_length attribute specified. please correct the following:\n--{0}'
                          .format('\n--'.join(messages)))