Home > Enterprise >  Create custom user model and Profile
Create custom user model and Profile

Time:11-16

Well I'm trying to create user addition form from frontend that creates user and additional info based on custom user model.But I'm getting duplicate key value violates unique constraint "users_driver_email_key" DETAIL: Key (email)=() already exists. here is my code:

Models.py

class CustomUser(AbstractUser):
    is_driver = models.BooleanField(default=False)
    is_accountant = models.BooleanField(default=False)
    is_dispatcher = models.BooleanField(default=False)



class Driver(models.Model):
    driver_user = models.OneToOneField(CustomUser, on_delete = models.CASCADE, primary_key = True)
    full_name = models.CharField(max_length=50, default=None)
    phone_number = models.CharField(max_length=50, default=None)
    email = models.EmailField(unique=True,max_length=255, default=None)
    address = models.CharField(max_length=70, default=None)
    country = models.CharField(max_length=50, default=None)
    state = models.CharField(choices=US_STATES,max_length=50, default=None)
    city = models.CharField(max_length=50, default=None)
    zipp = models.CharField(max_length=50, default=None)
    birth_date = models.DateField(default=None)
    license_no = models.IntegerField(default=None)
    license_exp_date = models.DateField(default=None)
    last_medical = models.DateField(default='', blank=True, null=True)
    next_medical = models.DateField(default='', blank=True, null=True)
    last_drug_test = models.DateField(default='', blank=True, null=True)
    next_drug_test = models.DateField(default='', blank=True, null=True)
    date_created = models.DateTimeField(auto_now_add=True)
    date_edited = models.DateTimeField(auto_now=True)
    status = models.IntegerField(choices=STATUS, default=1)

        
class DriversFiles(models.Model):
    file = models.FileField(upload_to="media/", blank=True, null=True)
    driver_files = models.ForeignKey('Driver', on_delete=models.CASCADE, default=None, null=True)

@receiver(post_save, sender=CustomUser)
def create_user_profile(sender, instance, created, **kwargs):
# if Created is true (Means Data Inserted)
if created:
    # Check the user_type and insert the data in respective tables
    if instance.is_driver:
        Driver.objects.create(
            driver_user=instance, 
            full_name = "123",
            phone_number = "123",
            email = "",
            address = "123",
            country = "123",
            state = "123",
            city = "123",
            zipp = "213",
            birth_date = '2022-01-01',
            license_no = '1234',
            license_exp_date = '2022-01-01',
            last_medical= '2022-01-01',
            next_medical = '2022-01-01',
            last_drug_test = '2022-01-01',
            next_drug_test = '2022-01-01',
            )

Views.py

def create_driver_view(request):
    if request.method == "POST":
        add_driver = DriverForm(request.POST)
        add_driver_file = request.FILES.getlist("file")
        
        if add_driver.is_valid():
            #For Custom User
            password = 'Ga20224$5%'
            full_name = add_driver.cleaned_data['full_name']
            email = add_driver.cleaned_data['email']
            phone_number = add_driver.cleaned_data['phone_number']
            address = add_driver.cleaned_data['address']
            country = add_driver.cleaned_data['country']
            state = add_driver.cleaned_data['state']
            city = add_driver.cleaned_data['city']
            zipp = add_driver.cleaned_data['zipp']
            birth_date = add_driver.cleaned_data['birth_date']
            license_no = add_driver.cleaned_data['license_no']
            
            license_exp_date = add_driver.cleaned_data['license_exp_date']
            last_medical = add_driver.cleaned_data['last_medical']
            next_medical = add_driver.cleaned_data['next_medical']
            last_drug_test = add_driver.cleaned_data['last_drug_test']
            next_drug_test = add_driver.cleaned_data['next_drug_test']
            print(email)
            username = email.split('@')[0]   uuid.uuid4().hex[:2]
            user = CustomUser.objects.create_user(
                username = username, 
                password = password, 
                is_driver = True, 
                email = email
                )
            
            #For Driver Profile
            user.driver.full_name = full_name
            user.driver.email = email
            user.save()
            # for i in add_driver_file:
            #     DriversFiles.objects.create(driver_files=user, file=i)
            return redirect('drivers:list_driver')  
        else:
            print(add_driver.errors)
            
    else:
        add_driver = DriverForm()
        add_driver_files = DriverFormUpload()

    return render(request, "drivers/add.html", {"add_driver": add_driver, "add_driver_files": add_driver_files})

I was getting eror {{message}} that username or email is already taken but now it opens debugger. In addition it creates user account with the same emails but then dont creates Driver table cause email is not unique.

I'm new in django and Just wanted to create custom user models, but there is so many headaches. What should I do here. or how can I create custom user models correctly

CodePudding user response:

As you are inheriting from AbstractUser class (see line 334), you already have an email field on your user instance. Thus, removing the email field from the driver model should fix your issue.

class AbstractUser(AbstractBaseUser, PermissionsMixin):
    """
    An abstract base class implementing a fully featured User model with
    admin-compliant permissions.
    Username and password are required. Other fields are optional.
    """

    username_validator = UnicodeUsernameValidator()

    username = models.CharField(
        _("username"),
        max_length=150,
        unique=True,
        help_text=_(
            "Required. 150 characters or fewer. Letters, digits and @/./ /-/_ only."
        ),
        validators=[username_validator],
        error_messages={
            "unique": _("A user with that username already exists."),
        },
    )
    first_name = models.CharField(_("first name"), max_length=150, blank=True)
    last_name = models.CharField(_("last name"), max_length=150, blank=True)
    email = models.EmailField(_("email address"), blank=True)

If you want to use the email field as auth and unique, you could approach it like so:

from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils.translation import ugettext_lazy as _

from .managers import CustomUserManager


class CustomUser(AbstractUser):
    username = None
    email = models.EmailField(_('email address'), unique=True)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    objects = CustomUserManager()

    def __str__(self):
        return self.email

CodePudding user response:

Django provided to facilities to customize the Default USER Model.

Have Two Famous approaches...

1 - Extending User Model Using a Custom Model Extending AbstractUser

from django.db import models
from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    bio = models.TextField(max_length=500, blank=True)
    location = models.CharField(max_length=30, blank=True)
    birth_date = models.DateField(null=True, blank=True)
    profile_pic = models.ImageField(upload_to ='/Propife/',null=True, blank=True)

2 - Extending User Model Using a Custom Model Extending AbstractBaseUser

from django.db import models
from django.core.mail import send_mail
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.base_user import AbstractBaseUser
from django.utils.translation import ugettext_lazy as _

from .managers import UserManager


class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(_('email address'), unique=True)
    first_name = models.CharField(_('first name'), max_length=30, blank=True)
    last_name = models.CharField(_('last name'), max_length=30, blank=True)
    date_joined = models.DateTimeField(_('date joined'), auto_now_add=True)
    is_active = models.BooleanField(_('active'), default=True)
    profile_pic = models.ImageField(upload_to ='/Propife/',null=True, blank=True)
    bio = models.TextField(max_length=500, blank=True)
    location = models.CharField(max_length=30, blank=True)
    birth_date = models.DateField(null=True, blank=True)

    objects = UserManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    class Meta:
        verbose_name = _('user')
        verbose_name_plural = _('users')

NOTE:- put all fields with null=True blank=True which you want to use for profile purpose. and create a form with CustomUserModel and then write the Update functionality for profile fields which leave with null=True blank=True.

  • Related