【问题标题】:How to override a form in django-rest-auth with my own custom form?如何用我自己的自定义表单覆盖 django-rest-auth 中的表单?
【发布时间】:2019-06-06 18:20:03
【问题描述】:

我正在使用 django-rest-auth,我正在尝试通过覆盖表单的一种方法来修复密码重置视图中的错误。虽然我已经用不同的 django-rest-auth 表单成功地完成了类似的事情,但我无法让它在这个表单上工作。无论我做什么,都使用旧形式。

api/urls.py

from django.urls import include, path
from django.contrib.auth import views
from django.conf.urls import include, url
from django.views.generic.base import RedirectView
from .forms import SetPasswordFormCustom
from .forms import PasswordResetFormCustom

urlpatterns = [
    path('password/reset/',
        views.PasswordResetView.as_view(form_class=PasswordResetFormCustom),
        name='rest_password_reset'),
    path('rest-auth/', include('rest_auth.urls')),
    path('rest-auth/registration/', include('rest_auth.registration.urls')),
    path('users/', include('users.urls')),
    path('reset/<uidb64>/<token>/',
        views.PasswordResetConfirmView.as_view(template_name='account/password_reset_confirm.html', form_class=SetPasswordFormCustom),
        name='password_reset_confirm'),
    path('reset/done/', views.PasswordResetCompleteView.as_view(template_name='account/password_reset_complete.html'),
        name='password_reset_complete'),
    path('content/', include('lists.endpoints')),
    # content is a path for lists, items etc found in the lists app
]

forms.py

from django import forms
from django.contrib.auth.forms import SetPasswordForm
from django.contrib.auth import (
    authenticate, get_user_model, password_validation,
)
from django.utils.translation import gettext, gettext_lazy as _
#from django.contrib.auth import password_validation

from django.contrib.auth.forms import PasswordResetForm
UserModel = get_user_model()

class SetPasswordFormCustom(SetPasswordForm):
    new_password1 = forms.CharField(
        label=_("New password"),
        widget=forms.PasswordInput(attrs={'class':'form-control','placeholder':'Password'}),
        strip=False,
    )
    new_password2 = forms.CharField(
        label=_("Confirm new password"),
        strip=False,
        widget=forms.PasswordInput(attrs={'class':'form-control','placeholder':'Confirm password'}),
        help_text=password_validation.password_validators_help_text_html(),
    )

class PasswordResetFormCustom(PasswordResetForm):
    def get_users(self, email):
        print('using custom form');
        """Given an email, return matching user(s) who should receive a reset.

        This allows subclasses to more easily customize the default policies
        that prevent inactive users and users with unusable passwords from
        resetting their password.
        """
        active_users = UserModel._default_manager.filter(**{
            '%s__iexact' % UserModel.get_email_field_name(): email,
            'is_active': True,
        })

        if not active_users:
            raise forms.ValidationError(_("The e-mail address is not assigned to any user account"),
                code='invalid')
        return (u for u in active_users if u.has_usable_password())

所以,我想不通的是没有使用 PasswordResetFormCustom 及其对 active_users 的检查。当我请求密码重置邮件时,服务器日志中没有打印“使用自定义表单”这一行,并且没有进行检查。

我的其他自定义表单 PasswordResetConfirmView 工作正常。

没有错误,所以不是导入不正确。

知道如何在无需编辑 django-rest-auth 文件的情况下自定义 get_users 方法吗?

感谢您的帮助!

编辑:我将 yofee 的代码放入一个文件 serializers.py 中,并且我还必须在 urls.py 中修复我的 url 路径的顺序。现在可以了!

urlpatterns = [ ... path('rest-auth/password/reset/', PasswordResetView.as_view()), 路径('rest-auth/',包括('rest_auth.urls')), ... ]

重置路径必须在包含之前。

【问题讨论】:

    标签: python django-forms django-rest-auth


    【解决方案1】:

    解决办法应该是

    1. 不在您的视图中设置PasswordResetFormCustom,而是在您的序列化程序中
    2. 使用rest_authPasswordResetView(不是Django 的)

    例子:

    from django.contrib.auth.forms import PasswordResetForm as DjangoPasswordResetForm
    from rest_auth.serializers import (
        PasswordResetSerializer as RestAuthPasswordResetSerializer
    )
    from rest_auth.views import PasswordResetView as RestAuthPasswordResetView
    from django.utils.translation import ugettext_lazy as _
    from rest_framework.exceptions import ValidationError
    
    class PasswordResetForm(DjangoPasswordResetForm):
        def get_users(self, email):
            users = tuple(super().get_users(email))
            if users:
                return users
            msg = _('"{email}" was not found in our system.')
            raise ValidationError({'email': msg.format(email=email)})
    
    
    class PasswordResetSerializer(RestAuthPasswordResetSerializer):
        password_reset_form_class = PasswordResetForm
    
    
    class PasswordResetView(RestAuthPasswordResetView):
        serializer_class = PasswordResetSerializer
    
        def __init__(self, *args, **kwargs):
            """Prints the name of the class if it is used."""
            print(self.__class__.__name__)
            super().__init__(*args, **kwargs)
    

    【讨论】:

    • 嗨,我已经尝试将您的代码放入一个新文件 api/serializers.py,并将视图导入我的 urls.py 并像这样使用它: from .serializers import PasswordResetView and path( '密码/重置/',PasswordResetView.as_view()),。但它没有显示错误,我认为它没有使用自定义表单。有什么建议?谢谢!
    • 很难说。你的代码看起来不错。您可以在 get_users 方法的开头添加 print('get_users called')。您能否将您正在使用的版本(Django、DRF、django-rest-auth)添加到您的问题中?你如何测试它?
    • 我添加了一个示例,如何测试是否使用了一个类。请将其添加到您的课程中,以查看哪些未调用。如果没有调用上述类,则意味着您的 urls.py 配置错误或使用了错误的 URL。
    • 谢谢你,我已经搞定了。我有一个路径错误,而且我忘记了自定义重置路径需要在之前定义一般的 rest-auth 路径包括。我已经习惯了以后的项目优先!
    猜你喜欢
    • 1970-01-01
    • 2016-03-09
    • 1970-01-01
    • 2011-02-05
    • 2014-04-13
    • 2012-11-11
    • 1970-01-01
    • 2013-04-20
    • 2011-03-29
    相关资源
    最近更新 更多