Django:如何检查用户名是否已经存在?

13

我不是很高级的Django用户。我在网上看到了很多不同的方法,但它们都是针对修改模型或者对我来说太复杂而无法理解的。
我正在我的MyRegistrationForm中重用UserCreationForm

class MyRegistrationForm(UserCreationForm):

    email = forms.EmailField(required=True)

    class Meta:
        model = User
        fields = ('username', 'email', 'password1', 'password2')

    def save(self, commit=True):
        user = super(MyRegistrationForm, self).save(commit=False)
        user.email = self.cleaned_data['email']
        user.set_password(self.cleaned_data["password1"])

        if commit:
            user.save()

        return user

我不知道如何判断用户输入的用户名是否已被使用,也不知道如何查找。因此,我只能使用以下代码将页面重定向到一个HTML页面,在那里显示“错误的用户名”或“密码不匹配”:

def register_user(request):
    if request.method == 'POST':
        form = MyRegistrationForm(request.POST)
        if form.is_valid():
            form.save()

            return HttpResponseRedirect('/accounts/register_success')
        else:
            return render_to_response('invalid_reg.html')
  

    args = {}
    args.update(csrf(request))

    args['form'] = MyRegistrationForm()
    print args
    return render_to_response('register.html', args)

这是我的注册模板(如有需要):

{% extends "base.html" %}

{% block content %}

<section>
<h2 style="text-align: center">Register</h2>
<form action="/accounts/register/" method="post">{% csrf_token %}

<ul>
{{form.as_ul}}
</ul>
<input type="submit" value="Register" onclick="validateForm()"/>

</form>

</section>
{% endblock %}

但是在用户被重定向之前,我需要引发某种异常或类似的情况。也许当用户按下注册时,他们会收到错误/警告,表示用户名已经被占用了。这是否可能?

4个回答

24

您可以使用exists

from django.contrib.auth.models import User

if User.objects.filter(username=self.cleaned_data['username']).exists():
    # Username exists
    ...

1
在我的情况下,这非常有效,而且您可以将其用于其他字段,不仅限于用户名。 - hardartcore

6
你可以使用clean_username方法检查username是否存在,并引发ValidationError
def clean_username(self, username):
    user_model = get_user_model() # your way of getting the User
    try:
        user_model.objects.get(username__iexact=username)
    except user_model.DoesNotExist:
        return username
    raise forms.ValidationError(_("This username has already existed."))

如果出现这种情况,您可以在注册表单中显示错误,无需重定向到另一个页面。

更新:

正如@Spacedman指出的关于在表单逻辑上检查用户名唯一性与DB级别上的竞争条件的有效观点,虽然您获得此机会的可能性非常小,但如果您确实有这样的情况,以下是相关的SO答案,值得一读:

如何避免Django中唯一检查的竞态条件

Django中的竞争条件

另一个更新

根据OP的评论,这里可以对视图进行另一个更改:

def register_user(request):
    # be DRY, the form can be reused for both POST and GET
    form = MyRegistrationForm(request.POST or None)

    # check both request is a POST and the form is valid
    # as you don't need to redirect for form errors, remove else block
    # otherwise it's going to redirect even form validation fails
    if request.method == 'POST' and form.is_valid():
        form.save()
        return HttpResponseRedirect('/accounts/register_success')
    # I use render so need not update the RequestContext, Django does it for you
    html = render(request, 'register.html', {'form': form})
    return HttpResponse(html)

希望这有所帮助。

3
用户名是唯一的,因此尝试创建它并捕获结果错误。这样,当另一个会话在您的会话测试存在并创建用户名之间测试相同的用户名时,您将避免竞争条件。 - Spacedman
@Spacedman,说得好。但通常user_model会有其他相关的模型(如address等),在form.save()下,user_model可能因为重复的username而无法创建,但是address记录可能已经被创建了? - Anzel
@Spacedman,看起来在处理竞态条件时,表单逻辑的清晰度会有所妥协。对于一般的流量网站,这应该不是问题,但对于边缘情况,我已经更新了答案,提供了一些有用的链接来解决它们(尽管我仍然觉得没有最清晰的方法来实现两者的最佳)。感谢您指出这一点,我也从阅读那些答案中受益匪浅 :-) - Anzel
大家好,我又来了。我已经试了好几天了,但是还是做不到。这似乎是不可能的。当我使用你们建议的代码时,什么也没有改变,我仍然被重定向到静态页面,上面显示“用户名或密码错误”。我真的很想学习如何在用户名字段附近产生错误 :(( - pptt
@pptt,请记得将clean_username代码块放在您的MyRegistrationForm中,而不是在views中。此外,您的views可以改进,我不确定为什么您需要更新csrf,它应该由Django自动更新。我会对我的答案进行另一个更新以反映这一点,请检查并报告是否适用于您。 - Anzel

2
如果您正在使用Django内置的UserCreationForm,那么只需在模板中键入以下内容:
{{form.errors}}

这将检查几乎所有内容,例如:

  1. 用户是否已创建
  2. 密码是否匹配

0

你可以在 models.py 中使用 unique=True

username = models.CharField(max_length=30, blank=True, null=True, unique=True)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接