【问题标题】:Django - redirect from form's clean methodDjango - 从表单的干净方法重定向
【发布时间】:2016-09-13 21:46:29
【问题描述】:

我在 django 中有一个登录表单,我需要在我的 clean 方法中做一些额外的检查:

class LoginForm(BootstrapFormMixin, forms.Form):
    email = forms.EmailField(required=True, max_length=30)
    password = forms.CharField(required=True, widget=forms.PasswordInput)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_id = self.__class__.__name__.lower()
        self.helper.form_action = ''

        self.helper.layout = Layout(
            Field('email'),
            Field('password'),
            Div(
                Submit('submit', _('Login'),
                       css_class="btn btn-block btn-success"),
                css_class=''
            )
        )

    def clean(self):
        email = self.cleaned_data.get('email')
        password = self.cleaned_data.get('password')

        user = authenticate(email=email, password=password)
        if user:
            company = user.company
            if not company.is_active:
                # here I want to make a redirect; if is it possible to add a flash message it would be perfect!
                raise forms.ValidationError(_('Account activation is not finished yet'))
        else:
            raise forms.ValidationError(_('Invalid credentials'))
        return self.cleaned_data

它可以正常工作,但是当凭据正确时,但名为 company 的用户相关对象未激活 (is_active=False) 我想将用户重定向到另一个视图并添加一些 flash 消息(可能使用 django.contrib.messages)。

是否可以进行这种重定向?

谢谢!

【问题讨论】:

  • view 负责返回 HTTP 响应(包括重定向)。表单负责处理输入数据。它们不返回响应,因此您无法从表单内部重定向。
  • 视图如何知道是否应该重定向或其他什么?我应该从表单中返回什么?

标签: python django django-forms django-views


【解决方案1】:

您可以在表单中添加一个布尔值 redirect 属性来知道何时进行重定向:

class LoginForm(BootstrapFormMixin, forms.Form):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.redirect = false

        . . . 

    def clean(self):
        email = self.cleaned_data.get('email')
        password = self.cleaned_data.get('password')

        user = authenticate(email=email, password=password)
        if user:
            company = user.company
            if not company.is_active:

                self.redirect = True

                raise forms.ValidationError()
        else:
            raise forms.ValidationError(_('Invalid credentials'))
        return self.cleaned_data


from django.contrib import messages
from django.shortcuts import redirect

def your_view(request):
    form = LoginForm(request.POST or None)

     if request.method == 'POST':
          if form.is_valid():
              # whatever
          else:
              if form.redirect:
                  messages.add_message(request, messages.ERROR,
                    _('Account activation is not finished yet'))
                  return redirect('wherever')

    return render(request, 'your-template.html', {'form': form})

【讨论】:

    【解决方案2】:

    当您在表单中提出验证错误时,您可以指定特定的错误代码。

    def clean(self):
            ...
            if not company.is_active:
                # here I want to make a redirect; if is it possible to add a flash message it would be perfect!
                raise forms.ValidationError(_('Account activation is not finished yet'), code='inactive')
    

    然后,在视图中,您可以检查错误代码,并在适当时重定向。您可以使用form.errors.as_data() 检查错误代码。由于您在clean 方法中引发了ValidationError,因此错误不属于特定字段,因此您可以使用__all__ 键访问它。

    if form.is_valid():
        # login user then redirect
    else:
        for error in form.errors.as_data()['__all__']:
            if error.code == 'inactive':
                messages.warning(request, 'Account is inactive')
                return redirect('/other-url/')
        # handle other errors as normal
    

    【讨论】:

      【解决方案3】:

      所以我冒着风险猜测您仍然希望在重定向用户之前先登录用户。

      如果上述情况属实,请先完成表单的 PRIMARY 功能。

      重定向可以在“视图”中运行,用户登录功能需要先运行,然后才能重定向用户。在此之前,无需运行额外的验证。

      这是我为视图编写 sn-p 的方式 - 仅显示与重定向相关的步骤(而不是整个视图)。假设 'home:index' 在用户登录后将用户路由到正常的重定向页面,而 'company:add_company_info' 将用户路由到带有消息的异常页面。

      if form.is_valid():
          user = form.login(request) # assume this form function calls django authenticate and will return the user if successful
          if user:
              login(request, user)
              if user.company.is_active: # this is assuming the user.company relationship exists
                  return redirect('home:index')
              else:
                  messages.add_message(request, messages.INFO, "Please fill in your company information")
                  return redirect('company:add_company_info')
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-07-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-11
        • 2018-10-18
        相关资源
        最近更新 更多