Alan Karanja
Alan Karanja

Reputation: 51

Custom user model doesn't create objects

I have created a CustomUser model and it has a one to relationship with my two other models.

class User(AbstractUser):
    is_learner = models.BooleanField(default=False)
    is_teacher = models.BooleanField(default=False)

class Teacher(models.Model):
    #teacher_name = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, primary_key=True)

class Learner(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, primary_key=True)

They do not show up when I try to create learner and teacher objects in their respective databases, as shown:

class LearnerSignUpForm(UserCreationForm):
    email = forms.EmailField()


    class Meta(UserCreationForm.Meta):
        #User = CustomUser
        model = CustomUser
        fields = ["username", "email", "password1", "password2"]
        #fields = UserCreationForm.Meta.fields + ("username", "email", "password1", "password2")

    @transaction.atomic
    def save(self, *args, **kwargs):
        user = super().save(commit=False)
        user.is_learner = True
        user.save()
        learner = Learner.objects.create(user=user)
        return user

How do I get it to save in learner and teacher tables respectively?

Upvotes: 0

Views: 183

Answers (1)

Swift
Swift

Reputation: 1711

Welcome to StackOverflow!

It is worth pointing that using model.objects.create(...) you're implicitly telling Django that you want to create the object with the specific values you give and save it. check the docs page here

If you wish to save an object for which has associated items, you can create a form and use a ModelChoiceField and provide the model and default choices using the choices kwarg. An example of a choices value would be YourUserModel.objects.all() However, I think in your case you may not want to give the user the freedome to make this choice, in which it would be correct to override the save() method of your form and create the intended logic.

Secondly, I have used Django for quite some time and never seen a Model.Meta class used in this way so forgive me if I'm mistaken, but I also think you need have your save() method directly on your LearnerSignupForm and not on the Meta class.

Thirdly, if you setup your forms correctly, using the correct types of fields, Django forms will deal with all the messy stuff for you and complain at you when you do something wrong (usually gracefully).

Lastly, I would highly recommend having a read through the docs page for creating new objects

Free code:

class LearnerSignUpForm(UserCreationForm):
    email = forms.EmailField()

    class Meta(UserCreationForm.Meta):
        model = CustomUser
        fields = ["username", "email", "password1", "password2"]

    @transaction.atomic
    def save(self, *args, **kwargs):
        user = super().save(commit=False)
        user.is_learner = True
        # create the relationship between the user and learner
        learner = user.learner_set.create(user=user)
        # user.learner_set.add(learner) # usually this way with FK
        user.save()
        return user # should this return the Learner object?

One final bit of advice:

Try to make your code as readable as possible! There's no reason that code can't be functional and beautiful! And where possible, you should make you class names and variable names as appropriate as possible, I would for example maybe use Student instead of Learner

Upvotes: 1

Related Questions