You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 12:01:51