我写了一个简短的代码片段来动态生成应用内的所有模型表单。对我而言,调用此代码段的最合理的位置是在应用程序的forms.py中。但这会导致循环导入,因为我试图在调用我的模块中设置属性,但它还不存在。这周围有优雅的方式吗?
import base.forms
import bomgar # bomgar is myapp
base.forms.generate_base_forms(bomgar)
from django.db import models
from django import forms
import inspect
class BaseForm(forms.ModelForm):
error_css_class = 'error'
required_css_class = 'required'
class Meta:
model=None
''' Generates a base set of forms to work off of. So I dont have to
make a billion of them by hand to start off. '''
def generate_base_forms(module):
__import__('%s.models' % module.__name__)
__import__('%s.forms' % module.__name__)
for model_name, model_class in inspect.getmembers(module.models):
if inspect.isclass(model_class):
if model_class._meta.abstract == False:
form_name=model_name+'Form'
class ModelMeta(BaseForm.Meta):
model=model_class
form_class=type(form_name,(BaseForm,), { 'Meta': ModelMeta })
setattr(module.forms, form_name, form_class)
(env)Macbook:djinmanage me$ ./manage shell
Python 2.7.1 (r271:86832, Jun 16 2011, 16:59:05)
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> import bomgar.models
>>> import bomgar.forms
<module 'bomgar.models' from '/Users/me/Sites/djinmanage/djinmanage/bomgar/models.pyc'>
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Users/me/Sites/djinmanage/djinmanage/bomgar/forms.py", line 4, in <module>
base.forms.generate_base_forms(bomgar)
File "/Users/me/Sites/djinmanage/djinmanage/base/forms.py", line 19, in generate_base_forms
print module.forms
AttributeError: 'module' object has no attribute 'forms'
>>>
答案 0 :(得分:1)
在绑定了所有必需的名称后,调用该函数在模块的 end 生成表单。
修改强>
好的,你导了它们。但是你让进口产品落在了地板上。
impmodule = __import__('%s.models' % module.__name__)
__import__('%s.forms' % module.__name__)
...
setattr(impmodule.forms, form_name, form_class)
(您不需要捕获第二个__import__
的结果,因为它们都是同一个模块。)
答案 1 :(得分:0)
所以我不完全确定进口的问题是什么。 Django似乎免费导入您的models.py文件,但不导入表单或视图。但我解决了我想要做的事情。我认为诀窍是__import__('xyz', fromlist=[*])
如果它们扩展了指定的类(我称之为我的base.models.BaseClass),这将为所有已安装的django应用程序生成所有模型表单。您可以将django.db.models.Model定位为父类,但我不知道扩展它的内容,因此您可以制作一堆您不想要的表单。也许有人会发现这个片段很有用。
import inspect
def get_module_classes(module):
'''
Returns a list of classes that aren't abstract for the given module.
'''
class_list = []
for model_name, klass in inspect.getmembers(module):
if inspect.isclass(klass) and hasattr(klass, '_meta') and klass._meta.abstract == False:
class_list.append(klass)
return class_list
'''
Searches your installed apps and creates a model form for every model that extends base.models.BaseObject.
The new form class is put in it's appropriate app.forms module. If the class name already exists(you defined it yourself),
then the new class is not generated.
'''
import types
import settings
import base.models
import base.forms
for app in settings.INSTALLED_APPS:
try:
models_module = __import__(app+'.models', fromlist=['*'])
forms_module = __import__(app+'.forms', fromlist=['*'])
for model_class in get_module_classes(models_module):
if issubclass(model_class, base.models.BaseObject):
form_name = model_class.__name__+'Form'
ModelMeta = types.ClassType('ModelMeta', (base.forms.BaseForm.Meta, ), { 'model': model_class })
FormClass = type(form_name, (base.forms.BaseForm, ), { 'Meta': ModelMeta })
if not hasattr(forms_module, form_name):
setattr(forms_module, form_name, FormClass)
except ImportError:
pass