0

I have created a form to add users in my front-end but the form does not validate duplicated username.I am using auth.user model.

This is my code:

views.py

from django.contrib.auth.models import User, Group    
@login_required(login_url='/login/')
    @permission_required('auth.add_user',raise_exception=True)
    def user_new(request):
        if request.method == "POST":

            form = NewUserForm(request.POST)

            if form.is_valid():
                user = form.save(commit=False)
                user.set_password(user.password)
                user.save()
                return redirect('userdetail', user.id)
        else:
            form = NewUserForm()
            return render(request, 'ace/user_edit.html', {'form': form}) 

forms.py

class NewUserForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ['username','first_name','last_name','password','email','is_active','is_staff','groups']
        widgets = {
        'username':TextInput(attrs={'class': u'form-control'}),
        'first_name':TextInput(attrs={'class': u'form-control'}),
        'last_name':TextInput(attrs={'class': u'form-control'}),
        'password':PasswordInput(attrs={'class': u'form-control'}),
        'email':EmailInput(attrs={'class': u'form-control'}),          
        'is_active':NullBooleanSelect(attrs={'class': u'form-control'}), 
        'is_staff':NullBooleanSelect(attrs={'class': u'form-control'}), 
        'groups':SelectMultiple(attrs={'class': u'form-control'}), 
        }  


    def clean_username(self):
        username = self.cleaned_data['username']
        user_exists = User.objects.get(username=username)
        if user_exists:
            raise ValidationError("User exists")

template

...

{% if form.errors %}

    {% for field in form %}
        {% for error in field.errors %}
            <div class="alert alert-danger">
                <strong>{{ error|escape }}</strong>
            </div>
        {% endfor %}
    {% endfor %}
    {% for error in form.non_field_errors %}
        <div class="alert alert-danger">
            <strong>{{ error|escape }}</strong>
        </div>
    {% endfor %}
{% endif %} 


<form method="POST" class="service-form">{% csrf_token %}

    {{ form.as_p }}
    <button type="submit" class="save btn btn-info">Salvar</button>

    <a href="{% url 'userlist' %}">
            <button class="btn btn-danger" type="button">Cancelar</button>
    </a>                                                   

</form>

...

When I create a new user OK, but when a try create a user that same username of other I get a error:

The view ace.views.user_new didn't return an HttpResponse object. It returned None instead.

If I add a print line "print form.errors" in view i get in console:

  • username
  • User exists
    • I don't think your form needs the `clean_username` method. It's a model form, so it should automatically check that the username is unique. – Alasdair May 16 '17 at 12:40

    4 Answers4

    2

    Your view does not have an else statement for if, form is not valid it should render the template with form errors.

    You need to change your view like this,

    def user_new(request): 
        if request.method == "POST": 
            form = NewUserForm(request.POST) 
            if form.is_valid(): 
                user = form.save(commit=False)
                user.set_password(user.password)
                user.save() 
                return redirect('userdetail', user.id) 
            else:
                return render(request, 'ace/user_edit.html', {'form': form})
        else: 
            form = NewUserForm() 
            return render(request, 'ace/user_edit.html', {'form': form})
    

    And also you need to add the tag {%for field in form%} {{field.error}}{%endfor%} along with the form fields and labels.

    zaidfazil
    • 9,017
    • 2
    • 24
    • 47
    0

    You need to make sure that your view returns a response for POST requests when the form is invalid. You can do this by moving the final return render() statement out of the else block.

    def user_new(request):
        if request.method == "POST":
    
            form = NewUserForm(request.POST)
    
            if form.is_valid():
                ...
                return redirect('userdetail', user.id)
        else:
            form = NewUserForm()
        return render(request, 'ace/user_edit.html', {'form': form}) 
    
    Alasdair
    • 298,606
    • 55
    • 578
    • 516
    0

    For registration django.contrib.auth User needs the username field to be unique. If you want to use other model field as unique (as unique registration field) and not the username, for example the email field, you can use this approach or use other registration bakends like django registration or django registration redux.

    Community
    • 1
    • 1
    doru
    • 9,022
    • 2
    • 33
    • 43
    0

    Instead of fixing the bug in your code I suggest to not invent the wheel and use excellent django-allauth package. It handles user login, logout, change password, registration and social sign in. I always start new projects from adding django-allauth - it handles all authentication problems with no effort.

    You can use the saved time and effort to write actual application code instead of solving trivial user management details.

    Also, the proper way to check for existence of the model instance is this:

        user_exists = User.objects.filter(username=username).exists()
        if user_exists:
            raise ValidationError("User exists")
    
    Eugene Morozov
    • 15,081
    • 3
    • 25
    • 32