[英]Passing request object from view to form in Django
I'm trying to create an account edit page which visually contains a single form (ie single submit button) but the fields are part of two (or more) different models. 我正在尝试创建一个帐户编辑页面,该页面在视觉上包含一个表单(即单个提交按钮),但这些字段是两个(或多个)不同模型的一部分。 I've pieced together a solution from several SO answers and the form loads fine on GET requests but I would now like to conditionally hide/display the terms of service checkbox field based on what url is being accessed.
我从几个SO答案中拼凑出一个解决方案,并且该表单在GET请求中可以很好地加载,但是我现在想根据所访问的URL有条件地隐藏/显示服务条款复选框字段。 Specifically on registration the TOS should be displayed while it should not on the account edit page.
特别是在注册时,应该在帐户编辑页面上显示TOS,而不应显示TOS。 Simplified code looks like so:
简化的代码如下所示:
# 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]
This is my first django project so it's possible that this is a completely wrong direction also. 这是我的第一个django项目,因此这可能也是一个完全错误的方向。 If so a hint towards a simpler solution would be appreciated.
如果这样的话,将有一个更简单的解决方案的提示。
As you are using class based view, I think you can try like this: 当您使用基于类的视图时,我认为您可以尝试如下操作:
view: 视图:
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))
Or like this: 或像这样:
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
And form is like this: 形式是这样的:
class RegistrationForm(forms.Form):
#form fields
def __init__(self, *args, request_data=None, **kwargs):
super().__init__(*args, **kwargs)
print(request_data)
# do other operations
I'm gonna keep it super simple. 我要让它超级简单。 If you need further details, please 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)
You may want to consider just having two separate forms. 您可能需要考虑仅使用两种单独的形式。 If the only difference is the one on the registration page has a terms of service checkbox, then that form class could inherit from the other class and have the extra form field.
如果唯一的区别是注册页面上的一个具有“服务条款”复选框,则该表单类可以从另一个类继承并具有额外的表单字段。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.