简体   繁体   中英

Django User model saves twice into database

I am trying to create multi user registration system with Django. However, anytime I call the save() method to save a User type, it saves into the User table twice. The funny thing about the second model that is saved is that many required fields are empty.

I am using a custom user model that I created from AbstractBaseUser . I also rewrote the forms for the CustomUser model. For the multiple user types, I am using a profile model (Student model has a OneToOne field to the user model)

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')

Anytime a user signs up, this is what the students table looks like: 学生报名后表

Also, this is what the users table look like after signup (with the multiple saves) 在此处输入图像描述

So how do I correct the multiple saves in the user table? Also, How is it even possible to save a model with most of the required fields empty?

As pointed out by @RaghavKundra, the line below was what caused the problem of saving multiple times to the database

class Student(User):

Instead of that, it should be class Student(models.Model):

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM