在Django中将请求对象从视图传递到表单

时间:2015-02-22 02:07:31

标签: python django

我正在尝试创建一个帐户编辑页面,该页面在视觉上包含单个表单(即单个提交按钮),但这些字段是两个(或更多)不同模型的一部分。我已经从几个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项目,所以这可能是一个完全错误的方向。如果是这样的话,我们将不胜感激地提出更简单的解决方案。

3 个答案:

答案 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)

您可能想要考虑只有两种不同的形式。如果唯一的区别是注册页面上的那个具有服务条款复选框,那么该表单类可以从其他类继承并具有额外的表单字段。