我正在尝试创建一个帐户编辑页面,该页面在视觉上包含单个表单(即单个提交按钮),但这些字段是两个(或更多)不同模型的一部分。我已经从几个SO答案拼凑出一个解决方案,并且表单在GET请求上加载正常但我现在想要根据访问的URL有条件地隐藏/显示服务条款复选框字段。特别是在注册时,应该显示TOS,而不应该在帐户编辑页面上显示。简化代码如下所示:
# views.py
class _RequestPassingFormView(FormView):
http_method_names = ['get', 'post', 'head', 'options', 'trace']
def get(self, request, *args, **kwargs):
# Pass request to get_form_class and get_form for per-request
# form control.
form_class = self.get_form_class(request)
form = self.get_form(form_class)
return self.render_to_response(self.get_context_data(form=form))
def post(self, request, *args, **kwargs):
# Pass request to get_form_class and get_form for per-request
# form control.
form_class = self.get_form_class(request)
form = self.get_form(form_class)
if form.is_valid():
# Pass request to form_valid.
return self.form_valid(request, form)
else:
return self.form_invalid(form)
def get_form_class(self, request=None):
return super(_RequestPassingFormView, self).get_form_class()
def get_form_kwargs(self, request=None, form_class=None):
return super(_RequestPassingFormView, self).get_form_kwargs()
def get_initial(self, request=None):
return super(_RequestPassingFormView, self).get_initial()
def get_success_url(self, request=None, user=None):
# We need to be able to use the request and the new user when
# constructing success_url.
return super(_RequestPassingFormView, self).get_success_url()
def form_valid(self, form, request=None):
return super(_RequestPassingFormView, self).form_valid(form)
def form_invalid(self, form, request=None):
return super(_RequestPassingFormView, self).form_invalid(form)
class AccountEditView(_RequestPassingFormView):
form_class = AccountEditForm
template_name = 'account_edit.html'
def form_valid(self, request, form):
success_url = self.get_success_url(request, new_user)
try:
to, args, kwargs = success_url
return redirect(to, *args, **kwargs)
except ValueError:
return redirect(success_url)
def get_success_url(selfself,request, user):
return '/account'
#forms.py
class CombinedFormBase(forms.Form):
form_classes = []
def __init__(self, *args, **kwargs):
super(CombinedFormBase, self).__init__(*args, **kwargs)
for f in self.form_classes:
name = f.__name__.lower()
setattr(self, name, f(*args, **kwargs))
form = getattr(self, name)
self.fields.update(form.fields)
self.initial.update(form.initial)
def is_valid(self):
isValid = True
for f in self.form_classes:
name = f.__name__.lower()
form = getattr(self, name)
if not form.is_valid():
isValid = False
# is_valid will trigger clean method
# so it should be called after all other forms is_valid are called
# otherwise clean_data will be empty
if not super(CombinedFormBase, self).is_valid() :
isValid = False
for f in self.form_classes:
name = f.__name__.lower()
form = getattr(self, name)
self.errors.update(form.errors)
return isValid
def clean(self):
cleaned_data = super(CombinedFormBase, self).clean()
for f in self.form_classes:
name = f.__name__.lower()
form = getattr(self, name)
cleaned_data.update(form.cleaned_data)
return cleaned_data
class RegistrationForm(forms.Form):
required_css_class = 'required'
email = forms.EmailField(label=_('E-mail'))
password1 = forms.CharField(widget=forms.PasswordInput,
label=_('Password'))
password2 = forms.CharField(widget=forms.PasswordInput,
label=_('Password (again)'))
"""
Conditionlly display TOS checkbox based on context
"""
def __init__(self, *args, **kwargs):
"""
add in a field for terms of service here if viewing
the registration form
"""
super(RegistrationForm, self).__init__(*args, **kwargs)
class AccountProfileForm(forms.Form):
required_css_class = 'required'
company = forms.CharField(label=('Company Name'))
class AccountEditForm(CombinedFormBase):
form_classes = [RegistrationForm, AccountProfileForm]
这是我的第一个django项目,所以这可能是一个完全错误的方向。如果是这样的话,我们将不胜感激地提出更简单的解决方案。
答案 0 :(得分:1)
当您使用基于类的视图时,我认为您可以尝试这样:
视图:
class _RequestPassingFormView(FormView):
http_method_names = ['get', 'post', 'head', 'options', 'trace']
def get(self, request, *args, **kwargs):
form_class = self.get_form_class()
self.object = None
form = form_class(request_data=request)
return self.render_to_response(self.get_context_data(form=form))
或者像这样:
class _RequestPassingFormView(FormView):
http_method_names = ['get', 'post', 'head', 'options', 'trace']
#No need to override the get method in this view.
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs.update(request_data=self.request)
return kwargs
形式是这样的:
class RegistrationForm(forms.Form):
#form fields
def __init__(self, *args, request_data=None, **kwargs):
super().__init__(*args, **kwargs)
print(request_data)
# do other operations
答案 1 :(得分:0)
我要保持它超级简单。如果您需要更多详细信息,请refer here:
def my_view(request):
if request.method == 'POST':
# Sending your request info as kwarg.
form = myform(request.POST, user=request.user)
class MyForm(forms.Form):
def __init__(self, *args, **kwargs):
# Recieving it.
self.user = (kwargs.pop('user', None))
super(MyForm, self).__init__(*args, **kwargs)
答案 2 :(得分:0)
您可能想要考虑只有两种不同的形式。如果唯一的区别是注册页面上的那个具有服务条款复选框,那么该表单类可以从其他类继承并具有额外的表单字段。