Django用户名大小写适配:注册转小写与登录iexact匹配实现
用户名大小写处理需求与实现咨询
需求与当前进展
- 注册要求:将用户输入的用户名转为小写存储,同时校验用户名是否已存在
- 登录要求:支持用户名大小写不敏感匹配,使用
iexact查询 - 当前进展:已在
AddCompanyForm中尝试添加clean_username方法实现用户名转小写,现需了解登录功能中iexact的具体实现位置和方式
相关代码
forms.py
class AddCompanyForm(forms.ModelForm): """ Add company model form """ name = forms.CharField(required=True) password = forms.CharField(widget=forms.PasswordInput()) logo = forms.ImageField(required=False) phone_number = forms.CharField(widget=forms.NumberInput()) label = forms.CharField(max_length=20) country = forms.ModelChoiceField(queryset=Country.objects.all()) city = forms.ModelChoiceField(queryset=City.objects.all()) area = forms.ModelChoiceField(queryset=Area.objects.all()) latitude = forms.CharField(max_length=50, required=False) longitude = forms.CharField(max_length=50, required=False) water_source = forms.ModelChoiceField(queryset=WaterSource.objects.all()) class Meta: model = User fields = ['name', 'username', 'email', 'password'] def __init__(self, *args, **kwargs): super(AddCompanyForm, self).__init__(*args, **kwargs) self.helper = FormHelper() self.helper.form_tag = False self.layout = Layout(Row(Column('name', css_class='form-group col-md-6 mb-0'), Column('username', css_class='form-group col-md-6 mb-0'), css_class='form-row'), Row(Column('email', css_class='form-group col-md-6 mb-0'), Column('password', css_class='form-group col-md-6 mb-0'), css_class='form-row'), Row(Column('phone_number', css_class='form-group col-md-6 mb-0'), Column('logo', css_class='form-group col-md-6 mb-0'), css_class='form-row'), Row(Column('label', css_class='form-group col'), css_class='form-row'), Row(Column('country', css_class='form-group col'), Column('city', css_class='form-group col'), Column('area', css_class='form-group col'), css_class='form-row'), Row(Column('latitude', css_class='form-group col'), Column('longitude', css_class='form-group col'), css_class='form-row'), Row(Column('water_source', css_class='form-group col'), css_class='form-row')) self.helper.layout = self.layout
views.py
class Companies(LoginRequiredMixin, UserPassesTestMixin, FormView, ListView): """ Company add edit delete view search paginator """ model = Company template_name = 'company/index.html' form_class = AddCompanyForm success_url = reverse_lazy('companies:index') object_list = Company.objects.all() def form_valid(self, form): user, created = User.objects.get_or_create(username=form.cleaned_data['username'], email=form.cleaned_data['email']) user.set_password(form.cleaned_data['password']) user.save() if created: address = Address(label=form.cleaned_data['label'], city=form.cleaned_data['city'], area=form.cleaned_data['area'], long=form.cleaned_data['longitude'], lat=form.cleaned_data['latitude'], country=form.cleaned_data['country']) address.save() company = Company(owner=user, name=form.cleaned_data['name'], phone_number=form.cleaned_data['phone_number'], logo=form.cleaned_data['logo'], address=address, water_source=form.cleaned_data['water_source']) company.save() return super().form_valid(form)
已尝试的代码
def clean_username(self): return self.cleaned_data['username'].lower()
解决方案
1. 完善注册时的用户名处理(含重复校验)
现有clean_username仅实现转小写,需补充重复校验逻辑,确保转小写后的用户名不重复:
def clean_username(self): username = self.cleaned_data['username'].lower() # 用iexact校验,避免大小写不同但实际重复的情况 if User.objects.filter(username__iexact=username).exists(): raise forms.ValidationError("该用户名已被注册") return username
修改后,form_valid中get_or_create使用的username已经是小写,不会出现重复注册问题。
2. 登录时实现大小写不敏感匹配(使用iexact)
根据登录实现方式,有以下几种方案:
方案一:自定义登录视图
如果是自行编写的登录视图,直接在查询用户时使用username__iexact:
from django.contrib.auth import authenticate, login from django.shortcuts import render, redirect def custom_login(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') # 忽略大小写查询用户 user = User.objects.filter(username__iexact=username).first() if user and user.check_password(password): login(request, user) return redirect('home') else: return render(request, 'login.html', {'error': '用户名或密码错误'}) return render(request, 'login.html')
方案二:自定义登录表单(适配Django自带登录视图)
重写AuthenticationForm的clean方法:
from django.contrib.auth.forms import AuthenticationForm class CustomAuthenticationForm(AuthenticationForm): def clean(self): username = self.cleaned_data.get('username') password = self.cleaned_data.get('password') if username and password: user = User.objects.filter(username__iexact=username).first() if not user or not user.check_password(password): raise forms.ValidationError("用户名或密码错误") self.user_cache = user return self.cleaned_data
然后在登录视图中使用该表单:
from django.contrib.auth.views import LoginView class CustomLoginView(LoginView): form_class = CustomAuthenticationForm template_name = 'login.html'
方案三:自定义认证后端(推荐)
创建backends.py文件,编写全局生效的认证后端:
from django.contrib.auth.backends import ModelBackend from django.contrib.auth import get_user_model User = get_user_model() class CaseInsensitiveModelBackend(ModelBackend): def authenticate(self, request, username=None, password=None, **kwargs): try: user = User.objects.get(username__iexact=username) except User.DoesNotExist: return None if user.check_password(password): return user return None
在settings.py中配置认证后端:
AUTHENTICATION_BACKENDS = [ 'your_app_name.backends.CaseInsensitiveModelBackend', # 可选保留默认后端 'django.contrib.auth.backends.ModelBackend', ]
此方案无需修改登录视图或表单,所有登录请求自动支持大小写不敏感匹配。
内容的提问来源于stack exchange,提问作者hind.hbashneh
相关产品推荐
相关产品推荐

