Я пытаюсь создать многопользовательскую систему регистрации с помощью Django. Однако каждый раз, когда я вызываю метод save() для сохранения типа User, он сохраняет модель в таблице User дважды. Самое интересное, что во второй сохраненной модели многие обязательные поля оказываются пустыми.

Я использую пользовательскую модель пользователя, которую я создал из AbstractBaseUser. Я также переписал формы для модели CustomUser. Для нескольких типов пользователей я использую модель профиля (модель студента имеет поле OneToOne для модели пользователя)

.

models.py:

class User(AbstractBaseUser, PermissionsMixin):
    # I've removed some unimportant code here
    email = models.EmailField(
        verbose_name='email address',
        max_length=255,
        unique=True,
    )
    
    class Types(models.TextChoices):
        STUDENT = 'STUDENT', 'Student'
        DEPARTMENT_USER = 'DEPARTMENT_USER', 'Department user'
        ADMIN = 'ADMIN', 'Admin'
    user_type = models.CharField(_('Type'), max_length=50, choices=Types.choices, default=Types.STUDENT)   
    
    first_name = models.CharField(_('First name'), max_length=70, blank=False, default="")     
    middle_name = models.CharField(_('Middle name'), max_length=70, blank=True, default="")         
    last_name = models.CharField(_('Last name'), max_length=70, blank=False, default="")   
           
    is_active = models.BooleanField(default=True)        
    is_staff = models.BooleanField(default=False) # a admin user; non super-user
    is_superuser = models.BooleanField(default=False) # a superuser
    last_login = models.DateTimeField(null=True, blank=True)
    date_joined = models.DateTimeField(auto_now_add=True)
    
    
    USERNAME_FIELD = 'email'
    EMAIL_FIELD = 'email'
    REQUIRED_FIELDS = ['user_type', 'first_name', 'last_name'] # Email & Password are required by default.
    
    objects = UserManager()
    
    class Meta:
        verbose_name = ('user')
        verbose_name_plural = ('users')
        #db_table = 'auth_user'
        abstract = False


class AccountConfirmed(models.Model):
    # Model to determine which users have confirmed their email addresses. 
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='accountconfirmed')
    email_confirmed = models.BooleanField(default=False)
    reset_password = models.BooleanField(default=False)

    class Meta:
        app_label = 'auth'

# When the user model is created, through signals an AccountConfirmed model is also created.
# The email_confirmed and reset_password field is set to false. 
@receiver(models.signals.post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
    if created:
        AccountConfirmed.objects.create(user=instance)
    instance.accountconfirmed.save()
    
######################################################
######################################################


class Student(User):
    # This is the model class for students
    user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True, related_name='students')
    matric_number = models.CharField(_('Matriculation number'), max_length=11, blank=False)
    department = models.CharField(_('Department'), max_length=40, blank=False)
    # has_graduated, level, etc. future possibilities    
    
    def __str__(self):
        return f'{self.user.email}'

forms.py:

class StudentSignupForm(UserCreationForm):
    # first_name = forms.CharField(max_length=70)     
    # middle_name = forms.CharField(max_length=70, required=False)         
    # last_name = forms.CharField(max_length=70)           
    matric_number = forms.CharField(min_length=10, max_length=11, help_text='Your Matric number must be 10 characters')
    department = forms.CharField(max_length=40, help_text='e.g Computer Science')  
    
    class Meta(UserCreationForm.Meta):
        model = User  
        fields = UserCreationForm.Meta.fields + ('matric_number', 'department')
    
    @transaction.atomic
    def save(self, commit=True):
        # Save the User instance and get a reference to it
        user = super().save(commit=False)      
        user.user_type = User.Types.STUDENT
        user.is_active = False
        #if commit:
        user.save()
        print(f' forms.py {user.email} {user.first_name}')
        student = Student.objects.create(user=user, matric_number=self.cleaned_data.get('matric_number'), department=self.cleaned_data.get('department'))
        # Add other details
        # Return User instance, not Student instance
        return user

views.py:

.
class StudentUserSignupView(CreateView):
    model = User
    template_name = 'account/signup.html'
    form_class = StudentSignupForm
    
    def get_context_data(self, **kwargs):
        kwargs['user_type'] = 'STUDENT'
        return super().get_context_data(**kwargs)
    
    def form_valid(self, form):
        user = form.save()
        #login(self.request, user)
        send_verification_mail(self, user)
        return redirect('verification_sent')

Когда пользователь регистрируется, вот как выглядит таблица студентов: Таблица студентов после регистрации

Также, вот как выглядит таблица пользователей после регистрации (с несколькими сохранениями) введите описание изображения здесь

Как исправить множественное сохранение в таблице пользователей? Кроме того, как вообще возможно сохранить модель, в которой большинство обязательных полей пусты?

David.B

Ответов: 1

Ответы (1)

Как указал @RaghavKundra, строка ниже была причиной проблемы многократного сохранения в базе данных

класс Студент(Пользователь):

Вместо этого должно быть так class Student(models.Model):

2022 WebDevInsider