pythonhtmldjangoforms

Only first placeholder displayed in Django's UserCreationForm


I'm trying to make a sign-up page with a customized user creation form - add placeholders to the fields. I'm trying to do it this way:

forms.py

class SignUpForm(UserCreationForm):
    email = EmailField(max_length=200)

    class Meta:
        model = User
        fields = UserCreationForm.Meta.fields + ("password1", "password2", "email")
        widgets = {
            'username': TextInput(attrs={'placeholder': 'Username'}),
            'email': EmailInput(attrs={'placeholder': 'Email'}),
            'password1': PasswordInput(attrs={'placeholder': 'Password'}),
            'password2': PasswordInput(attrs={'placeholder': 'Repeat password'}),
        }
views.py

def signup(request):
    if request.method == "POST":
        form = SignUpForm(request.POST)
        if form.is_valid():
            user = form.save()
            login(request, user)
            return HttpResponseRedirect(reverse("event:list"))
    else:
        form = SignUpForm()
    return render(request, "registration/signup.html", {"form": form})
signup.html

{% extends "base.html" %}
{% block signup %}class="active"{% endblock %}

{% block content %}

<form method="post">
    {% csrf_token %}
    <div class="form-group">
        {{ form.username }}
    </div>
    <div class="form-group">
        {{ form.email }}
    </div>
    <div class="form-group">
        {{ form.password1 }}
    </div>
    <div class="form-group">
        {{ form.password2 }}
    </div>
    <button type="submit">Sign up</button>
</form>

{% endblock %}

However, it only affects the username's placeholders - the other ones are unaffected.

What I've tried doing was to add the placeholder to the declaration of the email variable, which works. However, there has to be a simpler way to do it, and - even if I'd do that the passwords would still not have placeholders. I have also tried to make the fields variables, like email = CharField(TextInput(attrs{'placeholder': 'Email'}), but that didn't help too.

Tried doing it as in the "Adding placeholder to UserCreationForm in Django" thread, but that didn't change anything. Other threads too, that's probably due to Django's version. Each time before trying it out I delete the site's browsing data to make sure it's not a client-side problem.

I'm using Django 5.0.6.


Solution

  • In Django for ModelForm, you can override widgets with Meta.widgets for model fields only.

    In your case, there is only one model field in the form - username. The rest of the fields are not model fields, the email field too because it is overridden in the form.

    The easiest and fastest way is to override the render method:

    class SignUpForm(UserCreationForm):
        ... # your code without changes
        class Meta:
            ... # your code without changes
            widgets = {
            ...# your code without changes
            }
    
        def render(self, *args, **kwargs):
            for name, widget in self._meta.widgets.items():
                self[name].field.widget.attrs.update(widget.attrs)
            return super().render(*args, **kwargs)
    

    more here: https://docs.djangoproject.com/en/5.0/topics/forms/modelforms/#specifying-widgets-to-use-in-the-form-with-widgets