我有以下型号:
class Product(models.Model):
active = models.BooleanField(default=True)
name = models.CharField(max_length=40, unique=True)
acronym = models.CharField(max_length=3, unique=True)
bool1_name = models.CharField(max_length=60, blank=True, null=True)
bool1_default = models.BooleanField(default=False)
int1_name = models.CharField(max_length=60, blank=True, null=True)
int1_default = models.IntegerField(blank=True, null=True)
float1_name = models.CharField(max_length=60, blank=True, null=True)
float1_default = models.FloatField(blank=True, null=True)
date1_name = models.CharField(max_length=60, blank=True, null=True)
class ProductData(models.Model):
created = models.DateTimeField(default=datetime.now)
created_by = models.ForeignKey(User)
item = models.ManyToManyField(Item)
bool1_val = models.BooleanField(default=False)
int1_val = models.IntegerField(blank=True, null=True)
float1_val = models.FloatField(blank=True, null=True)
date1_val = models.DateField(blank=True, null=True)
class Item(models.Model):
product = models.ForeignKey(Product)
business = models.ForeignKey(Business)
我已将以下数据输入数据库:
# pseudo code
Product(1,'Toothpaste','TP','Is the toothpaste white?',1,,,'Weight',1,)
Product(1,'Milk','MLK',,,,,'Litres',2,'Best Before')
我希望能够根据ProductData
中定义的变量为Product
构建表单(创建基于表单的值 - 来自另一个的值-table )。我想要这样的东西:
class ProductDataForm(ModelForm):
def __init__(self,p,*args,**kwargs):
super(ProductDataForm, self).__init__(*args, **kwargs)
# if the values isn't set in the product
if p.bool1_name is None:
# hide the input
self.fields['bool1_val'].widget = forms.CharField(required=False)
else:
# else make sure the name the field name is the product name
self.fields['bool1_val'].widget = forms.BooleanField(label=p.bool1_name)
...
但是我在将Product
的实例传递给ProductDataForm
时遇到了问题。其他人说我可以使用BaseModelFormSet
,但是关于此的文献是粗略的,我不确定如何应用它。
修改
如果我创建一个包含我不想在ProductDataForm的 init 中显示的所有字段的数组,我该如何将这些字段传递给Meta类的排除。像这样:
class ProductDataForm(ModelForm):
def __init__(self,p,*args,**kwargs):
super(ProductDataForm, self).__init__(*args, **kwargs)
tempExclude = []
if not p.bool1_name:
tempExclude.append('bool1_val')
else:
self.fields['bool1_val'].label = p.bool1_name
self.Meta.exclude = tempExclude
class Meta:
model = ProductData
exclude = []
修改
我现在正试图将我要排除的字段存储在setting.py
文件中,如下所示:
# settings.py
SUBITEM_EXCLUDE_FIELDS = ['dave']
# views.py
def new_product_data_view(request,product='0'):
try:
i_fpKEY = int(product)
except ValueError:
raise Http404()
if not i_fpKEY:
t_fp = Product.objects.filter(active=1).order_by('id')[0]
else:
t_fp = Product.objects.get(id=i_fpKEY)
FieldsToExcludeFromProductDataForm(t_fp)
print "views.py > PRODUCTDATA_EXCLUDE_FIELDS = "+str(PRODUCTDATA_EXCLUDE_FIELDS)
siForm = ProductDataForm(t_fp, request.POST, auto_id='si_%s')
return render_to_response(...)
# middleware.py
def FieldsToExcludeFromProductDataForm(tempFP):
excludedFields = ['created','created_by','item']
if not tempFP.bool1_name:
excludedFields.append('bool1_val')
if not tempFP.int1_name:
excludedFields.append('int1_val')
...
for val in excludedFields:
PRODUCTDATA_EXCLUDE_FIELDS.append(val)
print "middleware.py > PRODUCTDATA_EXCLUDE_FIELDS = "+str(PRODUCTDATA_EXCLUDE_FIELDS)
# forms.py
class ProductDataForm(ModelForm):
# Only renames the fields based on whether the product has a name
# for the field. The exclusion list is made in middleware
def __init__(self,fp,*args,**kwargs):
super(ProductDataForm, self).__init__(*args, **kwargs)
if fp.bool1_name:
self.fields['bool1_val'].label = fp.bool1_name
if fp.int1_name:
self.fields['int1_val'].label = fp.int1_name
class Meta:
def __init__(self,*args,**kwargs):
super(Meta, self).__init__(*args, **kwargs)
print 'Meta > __init__ > PRODUCTDATA_EXCLUDE_FIELDS = '+str(PRODUCTDATA_EXCLUDE_FIELDS)
model = ProductData
print 'Meta > PRODUCTDATA_EXCLUDE_FIELDS = '+str(PRODUCTDATA_EXCLUDE_FIELDS)
#exclude = PRODUCTDATA_EXCLUDE_FIELDS
但是终端显示Meta
类很早就被处理了,因此无法获得新修改的PRODUCTDATA_EXCLUDE_FIELDS
:
Meta > PRODUCTDATA_EXCLUDE_FIELDS = ['dave']
[11/Jul/2011 15:51:31] "GET /page/profile/1/ HTTP/1.1" 200 11410
middleware.py > PRODUCTDATA_EXCLUDE_FIELDS = ['dave', 'created', 'created_by', 'item', 'bool1_val', 'int1_val']
views.py > PRODUCTDATA_EXCLUDE_FIELDS = ['dave', 'created', 'created_by', 'item', 'bool1_val', 'int1_val']
[11/Jul/2011 15:51:32] "GET /item/new/ HTTP/1.1" 200 5028
[11/Jul/2011 15:51:32] "GET /client/1/ HTTP/1.1" 200 5445
[11/Jul/2011 15:51:32] "GET /client/view/1/ HTTP/1.1" 200 3082
答案 0 :(得分:4)
为什么要使用exclude和metaclasses - 只需删除要排除的字段:
class ProductDataForm(ModelForm):
__init__():
...
for field_name in PRODUCTDATA_EXCLUDE_FIELDS:
del self.fields[field_name]
...
也许这不太对,但它很简单,而且很有效。
答案 1 :(得分:2)
你的想法很明显,但后来你试图以非常迂回的方式实现它。
Python允许您使用type()函数的三个参数形式在运行时动态创建类。
使用此功能的常用方法是使用factory函数,Django以django.forms.models.modelform_factory
的形式提供。
此功能未记录,但似乎是in progress。它来自与modelformset_factory
和inlineformset_factory
相同的函数系列,这些函数已记录在案,所以我说它可以安全使用。
签名是
modelform_factory(model, form=ModelForm, fields=None, exclude=None, formfield_callback=None)
model
,exclude
和fields
等同于您通常在表单的内部Meta
类中声明的内容(这就是它的实现方式)。
现在,要在您的示例中使用此功能,您需要稍微改变一下方法。首先导入工厂功能。
from django.forms.models import modelformset_factory
然后使用您的视图功能或类来:
excludedFields
)。创建表单类:
formClass = modelform_factory(ProductData, excludes=excludedFields)
像往常一样初始化您的表单,但使用formClass
而不是预定义的表单(ProductDataForm
)
form = formClass()
或form = formClass(request.POST)
等......