Django IntegrityError в /accounts/signup/: NOT NULL constraint failed: accounts_subject.gender

В основном я пытаюсь создать форму регистрации пользователя с несколькими дополнительными полями, чем это возможно в стандартной модели User. Поэтому я создал другую модель с отношением 1 к 1 с моделью User, и это работает (в админке django я могу создавать субъекты (именно так я называю этот класс "расширенный"), связанные с некоторым пользователем).

Когда я использую свою регистрационную форму, идея заключается в том, что создается пользователь (с обычными атрибутами: имя пользователя, email, пароль), а также субъект, связанный с этим пользователем, который имеет остальные атрибуты, которые я хочу сохранить (пол, уровень образования, год рождения и т.д.)

Но при его использовании в базе данных сохраняется только пользователь (тема не сохраняется) и я получаю следующую ошибку:

IntegrityError at /accounts/signup/
NOT NULL constraint failed: accounts_subject.gender

Вот мой код:

models.py:

from django.db import models
import uuid
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver

class Subject(models.Model):

    GENDER_CHOICES = (
        ('M', 'Masculino'),
        ('F', 'Femenina'),
    )
    EDUCATIONLEVEL_CHOICES = (
        ('P', 'Primaria'),
        ('S', 'Secundaria'),
        ('T', 'Terciaria'),
        ('U', 'Universitaria'),
    )
    id                   = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
    user                 = models.OneToOneField(User, on_delete=models.CASCADE)
    gender               = models.CharField(max_length=20, choices=GENDER_CHOICES, default=None)
    education_level      = models.CharField(max_length=20, choices=EDUCATIONLEVEL_CHOICES, default='P')
    email                = models.EmailField(max_length=50)
    nationality          = models.CharField(max_length=100, default='Argentina')
    country_of_residence = models.CharField(max_length=100, default='Argentina')
    year_of_birth        = models.IntegerField(default=None)
    experiment           = models.ManyToManyField(Experiment, default=None)
    points               = models.IntegerField(default=0)

    def __str__(self):
        return self.email

@receiver(post_save, sender=User)
def update_profile_signal(sender, instance, created, **kwargs):
    print(instance, type(instance))
    if created:
        try:
            Subject.objects.create(user=instance)
            instance.subject.save()
        except Subject.DoesNotExist:
            print("No se pudo crear un sujeto para este usuario")

forms.py:

from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm


class SignUpForm(UserCreationForm):
    GENDER_CHOICES = (
        ('M', 'Masculino'),
        ('F', 'Femenina'),
    )
    EDUCATIONLEVEL_CHOICES = (
        ('P', 'Primaria'),
        ('S', 'Secundaria'),
        ('T', 'Terciaria'),
        ('U', 'Universitaria'),
    )
    username = forms.CharField(max_length=30, help_text='Nombre de usuario', required=True)
    gender               = forms.TypedChoiceField(initial=1, choices=GENDER_CHOICES, help_text='Genero', required=False)
    education_level      = forms.TypedChoiceField(initial=1, choices=EDUCATIONLEVEL_CHOICES, help_text='Maximo nivel educativo alcanzado', required=False)
    email                = forms.EmailField(max_length=50, help_text='Email', required=False)
    nationality          = forms.CharField(max_length=100, help_text='Nacionalidad', required=False)
    country_of_residence = forms.CharField(max_length=100, help_text='Pais de residencia', required=False)
    year_of_birth        = forms.IntegerField(help_text='Año de nacimiento', required=False)

    class Meta:
        model = User
        fields = ('username', 'gender', 'education_level', 'email', 'nationality', 'country_of_residence', 'year_of_birth', 'password1', 'password2', )

views.py:

from django.shortcuts import render, redirect
from django.contrib.auth import login, authenticate
from django.contrib.auth.forms import UserCreationForm
from django.urls import reverse_lazy
from django.views import generic
from .forms import SignUpForm

def signup_view(request):
    form = SignUpForm(request.POST)
    if form.is_valid():
        user = form.save()

        user.refresh_from_db()
        user.subject.gender = form.cleaned_data.get('gender')
        user.subject.education_level = form.cleaned_data.get('education_level')
        user.subject.email = form.cleaned_data.get('email')
        user.subject.nationality = form.cleaned_data.get('nationality')
        user.subject.country_of_residence = form.cleaned_data.get('country_of_residence')
        user.subject.year_of_birth = form.cleaned_data.get('year_of_birth')

        user.save()
        username = form.cleaned_data.get('username')
        password = form.cleaned_data.get('password1')
        user = authenticate(username=username, password=password)
        login(request, user)
        return redirect('home')
    else:
        form = SignUpForm()
    return render(request, 'signup.html', {'form': form})

Если я пишу в атрибуте gender null = True ошибка не возникает, но даже если я помещаю в форму информацию для этого поля, она не сохраняется в базе данных.

Я искал решение этой проблемы на stackoverflow и пытался следовать некоторым советам, но пока безуспешно. Большое спасибо за помощь!

Вернуться на верх