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 и пытался следовать некоторым советам, но пока безуспешно. Большое спасибо за помощь!