如何用我自己的自定义表单覆盖 django-rest-auth 中的表单?
How to override a form in django-rest-auth with my own custom form?
我正在使用 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 的检查。当我请求密码重设电子邮件时,服务器日志中未打印行 "using custom form",并且未执行检查。
我的其他自定义表单 PasswordResetConfirmView 工作正常。
没有错误所以不是导入不正确。
知道如何自定义 get_users 方法而无需编辑 django-rest-auth 文件吗?
感谢您的帮助!
编辑:我将 yofee 的代码放入文件 serializers.py 中,而且我还必须修复 urls.py 中 url 路径的顺序。现在可以使用了!
url模式 = [
...
路径('rest-auth/password/reset/', PasswordResetView.as_view()),
路径('rest-auth/',包括('rest_auth.urls')),
...
]
重置路径必须在包含之前。
解决方法应该是
- 未在您的视图中设置
PasswordResetFormCustom
,但在您的序列化程序中设置
- 使用
rest_auth
的 PasswordResetView
(不是 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)
我正在使用 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 的检查。当我请求密码重设电子邮件时,服务器日志中未打印行 "using custom form",并且未执行检查。
我的其他自定义表单 PasswordResetConfirmView 工作正常。
没有错误所以不是导入不正确。
知道如何自定义 get_users 方法而无需编辑 django-rest-auth 文件吗?
感谢您的帮助!
编辑:我将 yofee 的代码放入文件 serializers.py 中,而且我还必须修复 urls.py 中 url 路径的顺序。现在可以使用了!
url模式 = [ ... 路径('rest-auth/password/reset/', PasswordResetView.as_view()), 路径('rest-auth/',包括('rest_auth.urls')), ... ]
重置路径必须在包含之前。
解决方法应该是
- 未在您的视图中设置
PasswordResetFormCustom
,但在您的序列化程序中设置 - 使用
rest_auth
的PasswordResetView
(不是 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)