kamcoder
kamcoder

Reputation: 75

Receiving Integrity Error from CustomUserModel form

I would like to create a form with my CustomUserModel as shown below, which has a extending model called customer.

class UserManager(BaseUserManager):
    def create_user(self, email, password=None,is_active=True, is_staff=False, is_admin=False):
        if not email:
            raise ValueError("Users must have email address")
        user_obj = self.model(email = self.normalize_email(email))
        if not password:
            raise ValueError("Users must have a password")

        user_obj.set_password(password)
        user_obj.staff = is_staff
        user_obj.admin = is_admin
        user_obj.active = is_active
        user_obj.save(using=self._db)

        return user_obj

    def create_staffuser(self,email,password=None):
        user = self.create_user(email, password=password,is_staff=True)

        return user

    def create_superuser(self, email, password=None):
        user = self.create_user(email, password=password, is_staff=True, is_admin=True)

        return user



class User(AbstractBaseUser):

    email = models.EmailField(max_length=255,unique=True)
    active = models.BooleanField(default=True)
    staff = models.BooleanField(default=False)
    admin = models.BooleanField(default=False)


    USERNAME_FIELD = 'email'
    # email and password are required by default
    REQUIRED_FIELDS = []

    objects = UserManager()

    def __str__(self):
        return self.email

    def get_full_name(self):
        return self.email

    def get_short_name(self):
        return self.email

    def has_perm(self, perm, obj=None):
        return True

    def has_module_perms(self, app_label):
        return True

    @property
    def is_staff(self):
        return self.staff

    @property
    def is_admin(self):
        return self.admin

    @property
    def is_active(self):
        return self.active


class Customer(models.Model):

    GENDER = (
            ('Male', 'Male'),
            ('Female', 'Female'),
            )

    TITLE = (
            ('Mr', 'Mr'),
            ('Mrs', 'Mrs'),
            ('Miss', 'Miss'),
            ('Ms', 'Ms'),
            ('Dr', 'Dr'),
            ('Sir', 'Sir'),
            ('Madam', 'Madam'),
            )



    user = models.OneToOneField(User,on_delete=models.CASCADE)
    title = models.CharField(max_length=200, null=True, choices=TITLE)
    first_name = models.CharField(max_length=200, null=True)
    middle_name = models.CharField(max_length=200, blank=True,default='')
    last_name = models.CharField(max_length=200, null=True)
    phone = models.CharField(max_length=200, null=True)
    country = CountryField()
    birth_year = models.CharField(max_length=4, null=True)
    gender = models.CharField(max_length=200, null=True, choices=GENDER)
    date_created = models.DateTimeField(auto_now=True, null=True)
    profile_pic = models.ImageField(null=True, blank=True)
    last_purchase = models.DateTimeField(blank=True, null=True)


    def __str__(self):
        return self.user.email


Below shows my views.py to create a new customer/user form, that I would like to create at the same time.


@login_required(login_url='login')
def NewCustomerProfile(request):
    user_form = RegisterForm()
    customer_form = CustomerProfileForm()
    if request.method == 'POST':
        user_form = RegisterForm(request.POST)
        customer_form = CustomerProfileForm(request.POST)

        if user_form.is_valid() and customer_form.is_valid():
            user_form.save()
            customer_form.save()
            return redirect('/')
    return render(request, 'accounts/new_customer_profile.html', {'user_form': user_form,'customer_form':customer_form})

And see below showing my forms for both of the models


class CustomerProfileForm(ModelForm):
    class Meta:
        model = Customer
        fields = ['title','first_name','middle_name','last_name','phone','country','birth_year','gender']

class RegisterForm(forms.ModelForm):
    """
    A form for creating new users. Includes all the required
    fields, plus a repeated password.
    """
    password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)

    class Meta:
        model = User
        fields = ('email','admin', 'active')

I have been getting an error as shown below

IntegrityError at /new_customer_profile/
NOT NULL constraint failed: accounts_customer.user_id

Problem is new customer can be created once a user has been established and created. I would like to create a new user and customer at the same time with no errors accordingly to the models, forms and views shown above.

How does one come to the solution?

Upvotes: 1

Views: 50

Answers (2)

user1600649
user1600649

Reputation:

A ModelForm when saved returns the instance. In addition it has parameter that allows you not to save the model to the database. Combine these two and there's your solution:

        if user_form.is_valid() and customer_form.is_valid():
            user = user_form.save()
            customer = customer_form.save(commit=False)
            customer.user = user
            customer.save()
            return redirect('/')

Upvotes: 2

Milo Persic
Milo Persic

Reputation: 1118

I think you answer your own question, in a sense:

"Problem is new customer can be created once a user has been established and created."

Re-write your view to logic to do this in the order that it actually works. It can still happen "at the same time" relative to to the user, even when your view is doing it sequentially.

Upvotes: 0

Related Questions