我正在使用Django个人资料,并受到James Bennett的启发,创建了一个动态表格(http://www.b-list.org/weblog/2008/nov/09/dynamic-forms/)
我需要的是一个公司字段,当user_type为'pro'时,该字段仅显示在我的用户个人资料表单中。 基本上我的模型和形式看起来像:
class UserProfile(models.Model):
user_type = models.CharField(...
company_name = models.CharField(...
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
exclude = ('company_name',)
我在 init 中添加了company_name字段,就像James Bennett所示:
def __init__(self, *args, **kwargs):
super(UserProfileForm, self).__init__(*args,**kwargs)
if (self.instance.pk is None) or (self.instance.user_type == 'pro'):
self.fields['company_name'] = forms.CharField(...
问题在于,当我尝试保存()UserProfileForm的实例时,不保存字段'company_name'...
我通过在save()方法中显式调用该字段来解决这个问题:
def save(self, commit=True):
upf = super(UserProfileForm, self).save(commit=False)
if 'company_name' in self.fields:
upf.company_name = self.cleaned_data['company_name']
if commit:
upf.save()
return upf
但是我对这个解决方案不满意(如果有更多的领域会怎么样?Django的美丽是什么?等等)。它让我在晚上试图让模型表识别 init 中的新company_name字段。
这就是我最终在stackoverflow上发布此内容的故事......
答案 0 :(得分:3)
我会从表单中删除此逻辑并将其移至工厂。如果您的逻辑是在工厂,您可以有两种形式:
ProUserProfileForm继承自UserProfileForm并仅更改“exclude”常量。
您将拥有以下工厂:
def user_profile_form_factory(*args, instance=None, **kwargs):
if (self.instance.pk is None) or (self.instance.user_type == 'pro'):
cls = ProUserProfileForm
else:
cls = UserProfileForm
return cls(*args, instance, **kwargs)
答案 1 :(得分:1)
您希望何时设置user_type
属性?这似乎应该由javascript处理,而不是试图用模型形式做有趣的事情。
如果您希望company_name
字段在客户端指定为pro
后显示在客户端上,则可以使用javascript“取消隐藏”该字段。
如果相反,他们已被指定为pro
用户,则使用包含company_name
字段的其他表单。您可以按以下方式对原始模型表单进行子类化。
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
exclude = ('company_name',)
class UserProfileProForm(UserProfileForm):
class Meta:
exclude = None # or maybe tuple() you should test it
然后在您的视图中,您可以决定要呈现的表单:
def display_profile_view(request):
if user.get_profile().user_type == 'Pro':
display_form = UserProfileProForm()
else:
display_form = UserProfileForm()
return render_to_response('profile.html', {'form':display_form}, request_context=...)
在我看来,这是首选方式。它不依赖任何花哨的东西。代码重复很少。很清楚,也很期待。
修改:(以下建议的解决方案不起作用)
您可以尝试更改元类的exclude
,并希望在尝试确定是否包含该字段时,它会使用exclude的实例版本。给定一个表单的实例:
def __init__(self, *args, **kwargs):
if self.instance.user_type == 'pro':
self._meta.exclude = None
不确定这是否有效。我相信_meta
字段是实例化后使用的字段,但我没有验证这一点。如果它不起作用,请尝试撤消这种情况。
def __init__(self, *args, **kwargs):
if self.instance.user_type != 'pro':
self._meta.exclude = ('company_name',)
并在模型表单声明中完全删除排除字段。我提到这个替代方案的原因是因为看起来元类(元类的python意义)甚至在调用__init__
函数之前就会排除字段。但是如果你声明要在之后排除该字段,它将存在但不会被渲染..也许。我不是100%使用我的python Meta Class知识。祝你好运。
答案 2 :(得分:1)
我似乎找到了解决方案:
def AccountFormCreator(p_fields):
class AccountForm(forms.ModelForm):
class Meta:
model = User
fields = p_fields
widgets = {
'photo': ImageWidget()
}
return AccountForm
#...
AccountForm = AccountFormCreator( ('email', 'first_name', 'last_name', 'photo', 'region') )
if request.POST.get('acforms', False):
acform = AccountForm(request.POST, request.FILES, instance=request.u)
if acform.is_valid():
u = acform.save()
u.save()
ac_saved = True
else:
acform = AccountForm(instance = request.u)
答案 3 :(得分:0)
如何从Meta类中删除 exclude =('company_name',)?我认为这就是 save()不保存 company_name 字段的原因