Django4导入rest_auth LoginView报ugettext_lazy导入错误如何解决
实现登录API时引入from rest_auth.views import LoginView,代码中未直接导入ugettext_lazy,编写的登录视图代码如下:
from rest_auth.views import LoginView from django.contrib.auth import authenticate, login, logout from .serializers import LoginUserSerializer class Login(LoginView): def post(self, request, *args, **kwargs): serializer = LoginUserSerializer(data=request.data) serializer.is_valid(raise_exception=True) user = serializer.validated_data['user'] login(request, user) return super().post(request, format=None)
运行项目时抛出如下ImportError报错:
File "filePath\ProjectName\app1\urls.py", line 4, in <module> from .login import Login File "filePath\ProjectName\app1\login.py", line 1, in <module> from rest_auth.views import LoginView File "\myenv\lib\site-packages\rest_auth\views.py", line 9, in <module> from django.utils.translation import ugettext_lazy as _ ImportError: cannot import name 'ugettext_lazy' from 'django.utils.translation' ("\myenv\lib\site-packages\django\utils\translation\__init__.py")
目前查到的多数方案建议将Django 4版本降级至3.x版本,但当前已使用simple jwt实现令牌认证,需要除Django版本降级外的修复方案,以及可行的登录API实现建议。
报错根源是Django 4.0及以上版本移除了django.utils.translation模块下ugettext_lazy、ugettext等带u前缀的翻译函数别名,统一使用gettext_lazy等不带u前缀的函数,而引入的django-rest-auth库已停止维护多年,未做Django 4+版本适配,才触发导入错误。可选择以下任意一种方案解决:
方案1:猴子补丁兼容(不降级Django、不替换现有依赖)
不需要改动第三方库源码,只需要在项目根路由文件(根urls.py)的最顶部,也就是所有rest_auth相关导入代码之前,添加如下兼容代码,手动给translation模块补上缺失的别名即可:
from django.utils import translation # 兼容旧版rest_auth对Django4+的导入错误 translation.ugettext_lazy = translation.gettext_lazy translation.ugettext = translation.gettext translation.ungettext_lazy = translation.ngettext_lazy translation.ungettext = translation.ngettext
注意:这段代码必须放在所有rest_auth模块导入逻辑之前执行,否则补丁不会生效。
方案2:替换为持续维护的兼容依赖(推荐)
django-rest-auth早已停止维护,目前社区维护的兼容分支为dj-rest-auth,原生适配Django 4+、Django 5+版本,也原生支持Simple JWT,不需要额外打补丁,迁移成本极低:
- 卸载旧依赖:执行命令
pip uninstall django-rest-auth - 安装新依赖:执行命令
pip install dj-rest-auth - 全局替换导入路径:将代码中所有
from rest_auth.xxx import xxx替换为from dj_rest_auth.xxx import xxx,比如原代码的from rest_auth.views import LoginView改为from dj_rest_auth.views import LoginView即可,原有业务逻辑不需要改动 - 修改配置:将
settings.py的INSTALLED_APPS列表中'rest_auth'替换为'dj_rest_auth',如果用到注册等附加模块对应替换即可
方案3:自行实现登录接口(可控性最高)
既然已经接入Simple JWT,完全可以不依赖第三方认证库的登录视图,自行实现逻辑,彻底避免依赖兼容问题,示例实现如下:
- 编写序列化器
serializers.py:
from django.contrib.auth import authenticate from rest_framework import serializers from rest_framework_simplejwt.tokens import RefreshToken class LoginUserSerializer(serializers.Serializer): username = serializers.CharField(required=True) password = serializers.CharField(required=True, write_only=True) def validate(self, attrs): user = authenticate(username=attrs['username'], password=attrs['password']) if not user: raise serializers.ValidationError("用户名或密码错误") if not user.is_active: raise serializers.ValidationError("当前账号已被禁用") # 生成jwt令牌 refresh = RefreshToken.for_user(user) return { 'user': user, 'refresh': str(refresh), 'access': str(refresh.access_token) }
- 编写视图逻辑
views.py:
from rest_framework.views import APIView from rest_framework.response import Response from django.contrib.auth import login from .serializers import LoginUserSerializer class LoginView(APIView): def post(self, request): serializer = LoginUserSerializer(data=request.data) serializer.is_valid(raise_exception=True) user = serializer.validated_data['user'] # 维持session登录状态(如果不需要session认证可以删掉这行) login(request, user) return Response({ 'code': 200, 'msg': '登录成功', 'data': { 'access_token': serializer.validated_data['access'], 'refresh_token': serializer.validated_data['refresh'], 'username': user.username } })
该方案完全自主可控,后续扩展登录逻辑(比如加图片验证码、登录日志记录、手机号/邮箱多字段登录)都更灵活,不会被停更的第三方依赖限制。
内容的提问来源于stack exchange,提问作者Vinay Kumar

