Creating a simple multiple users app in Django

So I’ve created 3 different users: admins, developers, and project managers. When I use the individual signup forms for each of these users and log out, it works, but then I when try to use the login form, it seems to me that it’s acting like the signup form. Because when I input the same user details as the one I just created into the login form, it throws up the built-in error message, 'A user with that user name already exists' I’m not sure how to proceed from here.

Here’s what I have so far.

models.py

class CustomUser(AbstractUser):
    ACCOUNT_TYPE_CHOICES = (
        ('admin', 'Admin'),
        ('developer', 'Developer'),
        ('project_manager', 'Project Manager')
    )
    account_type = models.CharField(max_length=20, choices=ACCOUNT_TYPE_CHOICES)

login and signupviews

class LoginView(View):
    def get(self, request):
        # Render the login form
        form = LoginForm()
        return render(request, 'users/login.html', {'form': form})

    def post(self, request):
        # Get the form data from the request
        form = LoginForm(request.POST)

        # Validate the form data
        if form.is_valid():
            # Get the username and password from the form
            username = form.cleaned_data['username']
            password = form.cleaned_data['password']

            # Authenticate the user
            user = authenticate(request, username=username, password=password)

            # If the user is authenticated, log them in and redirect to the homepage
            if user is not None:
                login(request, user)
                if user.account_type == 'admin':
                    return redirect('admin_home')
                elif user.account_type == 'developer':
                    return redirect('developer_home')
                elif user.account_type == 'project_manager':
                    return redirect('projectmanager_home')
                return redirect('home')

            # If the user is not authenticated, render the login form again with an error message
            else:
                form.add_error(None, 'Invalid username or password')
                return render(request, 'users/login.html', {'form': form})
        else:
            return render(request, 'users/login.html', {'form': form})

class LogoutView(View):
    def get(self, request):
        # Log out the user and redirect to the login page
        logout(request)
        return redirect('home')
    
class AdminSignUpView(CreateView):
    form_class = AdminSignUpForm
    template_name = 'users/admin_signup.html'
    success_url = '/admin_home/'

    def form_valid(self, form):
        # Create the user and log them in
        user = form.save()
        login(self.request, user)
        return redirect(self.success_url)    
    
class DeveloperSignUpView(CreateView):
    form_class = DeveloperSignUpForm
    template_name = 'users/developer_signup.html'
    success_url = '/developer_home/'

    def form_valid(self, form):
        # Create the user and log them in
        user = form.save()
        login(self.request, user)
        return redirect(self.success_url)
    
class ProjectManagerSignUpView(CreateView):
    form_class = ProjectManagerSignUpForm
    template_name = 'users/projectmanager_signup.html'
    success_url = '/projectmanager_home/'

    def form_valid(self, form):
        # Create the user and log them in
        user = form.save()
        login(self.request, user)
        return redirect(self.success_url)
    

forms.py

class AdminSignUpForm(forms.ModelForm):
    # Define the form fields for the admin sign-up form
    account_type = forms.CharField(max_length=20, widget=forms.HiddenInput(), initial='admin')
    first_name = forms.CharField(max_length=30)
    last_name = forms.CharField(max_length=30)
    email = forms.EmailField()
    username = forms.CharField(max_length=150)
    password = forms.CharField(max_length=128, widget=forms.PasswordInput())

    class Meta:
        model = CustomUser
        fields = ['first_name', 'last_name', 'email', 'username', 'password']
        
class DeveloperSignUpForm(forms.ModelForm):
    # Define the form fields for the developer sign-up form
    account_type = forms.CharField(max_length=20, widget=forms.HiddenInput(), initial='developer')
    first_name = forms.CharField(max_length=30)
    last_name = forms.CharField(max_length=30)
    email = forms.EmailField()
    username = forms.CharField(max_length=150)
    password = forms.CharField(max_length=128, widget=forms.PasswordInput())

    class Meta:
        model = CustomUser
        fields = ['first_name', 'last_name', 'email', 'username', 'password']
        
class ProjectManagerSignUpForm(forms.ModelForm):
    # Define the form fields for the project manager sign-up form
    account_type = forms.CharField(max_length=20, widget=forms.HiddenInput(), initial='project_manager')
    first_name = forms.CharField(max_length=30)
    last_name = forms.CharField(max_length=30)
    email = forms.EmailField()
    username = forms.CharField(max_length=150)
    password = forms.CharField(max_length=128, widget=forms.PasswordInput())

    class Meta:
        model = CustomUser
        fields = ['first_name', 'last_name', 'email', 'username', 'password']
        
class LoginForm(forms.ModelForm):
    class Meta:
        model = CustomUser
        fields = ['username', 'password']
        widgets = {
            'password': forms.PasswordInput(),
        }

login template

{% block content %}
    <h1>Login</h1>
    <form method="post">
        {% csrf_token %}
        {{ form.as_p }}
        <button type="submit">Log in</button>
    </form>
    {% if form.errors %}
        <p>Your username and password didn't match. Please try again.</p>
    {% endif %}
{% endblock %}

urls.py

urlpatterns = [
    path('', views.home, name='home'),
    path('login/', views.LoginView.as_view(), name='login'),
    path('logout/', views.LogoutView.as_view(), name='logout'),
    path('admin_signup/', views.AdminSignUpView.as_view(), name='admin_signup'),
    path('developer_signup/', views.DeveloperSignUpView.as_view(), name='developer_signup'),
    path('projectmanager_signup/', views.ProjectManagerSignUpView.as_view(), name='projectmanager_signup'),
    path('admin_home/', views.admin_home, name='admin_home'),
    path('developer_home/', views.developer_home, name='developer_home'),
    path('projectmanager_home/', views.project_manager_home, name='projectmanager_home'),
]

login templates

{% block content %}
    <h1>Login</h1>
    <form method="post">
        {% csrf_token %}
        {{ form.as_p }}
        <button type="submit">Log in</button>
    </form>
    {% if form.errors %}
        <p>Your username and password didn't match. Please try again.</p>
    {% endif %}
{% endblock %}

base templates

<!doctype html>
<html>
  <head>
    <title>My Site</title>
  </head>
  <body>
    <h1>Welcome to My Site</h1>
    <p>
      <a href="{% url 'admin_signup' %}">Sign up as an admin</a>
      <a href="{% url 'developer_signup' %}">Sign up as a developer</a>
      <a href="{% url 'projectmanager_signup' %}">Sign up as a project manager</a>
      <a href="{% url 'login' %}">Sign In</a>
    </p>
    {% block content %}{% endblock %}
  </body>
</html>

Let me know if you need any more information.

Please post your urls.py file containing the references to these views.

Edited the question and code

When you’re going to one of these urls, are you entering the url directly, or are you selecting the url from some type of menu? If the latter, please post the template and any related data for that menu. Also, try entering the login/ url directly instead of using the menu.

Edited the question and code. And yes, I am selecting the url from a base template. I’ve added the base template as well

I think what you want to do is not make the LoginForm a model form. Your LoginForm isn’t intended to edit or add a new user - you would be better off making it a regular form with the username and password fields.
(I’m not in a position to verify this at the moment, but my current conjecture is that the model form - having been rendered without an instance - is treated like a “create” form, and the validation is finding the duplicate username, which is causing the error.)

1 Like

So I’ve changed the Login Form so now it looks like this

class LoginForm(forms.Form):
    username = forms.CharField(max_length=150)
    password = forms.CharField(max_length=128, widget=forms.PasswordInput())

However, this is now throwing up the error that the username and password didn't match, I’ve tested it multiple times using a simple login credentials that I know I wouldn’t mistype. I know that the Users are being created because when I use the signupforms, it redirect correctly and logouts correctly as well. The only thing that’s not working is the Login functionality. How should I proceed?

I just reviewed your views creating users - you’re not encrypting the passwords.

You should review how the user creation forms within the admin app work to see how a user registration should be done.