How to take boolean field input from HTML into my Django model?

Viewed 771

I have used Django forms for creating users and I extended the default User model by adding a boolean field, so I defined a new form for it. But I couldn't take input from HTML form to this boolean field. Shall I change my HTML form code? Following are my code samples:

models.py

# accounts.models.py
from django.db import models
from django.contrib.auth.models import User


class SpecialUser(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    flag = models.BooleanField()

    def __str__(self):
        return self.title

forms.py

from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from django.forms.widgets import CheckboxInput
from .models import SpecialUser

class RegisterForm(UserCreationForm):
    email = forms.EmailField()
    class Meta:
        model = User
        fields = ["username", "email", "password1", "password2"]

class SuperUserForm(forms.ModelForm):
    class Meta:
        model = SpecialUser
        fields = ['flag']
        widgets = {
            'flag': CheckboxInput(attrs={'class': 'flag'}),
        }

views.py

def register(request):
    if request.method == 'POST':
        form = RegisterForm(request.POST)
        sp_form = SuperUserForm(request.POST)
        if form.is_valid() and sp_form.is_valid():
            user = form.save()
            sp_form = sp_form.save(commit=False)
            sp_form.user = user
            sp_form.save()
            messages.success(request, 'Account created!')
            return redirect('login')
    else:
        form = RegisterForm()
        sp_form = SuperUserForm()
        messages.warning(request, 'Your account cannot be created.')
    return render(request, 'register.html', {'form': form})

HTML form code:

<form method="post" class="form-group">
    {% csrf_token %}
    {{ form|crispy }}
    <label for="flag">Special User: </label>
    <input id="flag" class="flag" type="checkbox" name="flag">
    <button type="submit" class="btn btn-success">Sign up</button>
</form>
2 Answers

For starters this is generally not how you would want to extend the user model in a Django application. You would want to inherit from AbstractUser and add your fields to that model and run migrations. At least in this case, that would be ideal, then you could simply define the field on your RegisterForm.fields and let {{ form|crispy }} render the form for you. Naturally, you could call form.save() and move on with your life.

To clarify why this may not be working, it is generally not good practice to render your own fields for a form unless absolutely necessary. If you insist on doing it this way, note that Django prefixes the id with id_ so in your case it would be <label for="id_name">...</label> and <input id="id_flag" ...

In your views.py you're creating a local variable for a SpecialUser form, sp_form, that is neither loaded into the context data nor templated in the HTML form code.

You can load sp_form into the context data by adding it to the context dict passed to render(). This will allow the template to see the variable. For example:

    return render(request, 'register.html', {'form': form, 'sp_form': sp_form})

And then you can render it in the template. For example, underneath the main form:

{{ form|crispy }}
{{ sp_form|crispy }}
Related