简体   繁体   English

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

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM