title: Customizing the Django User model - username as a Primary Key attribute
body: <p>How to can I create my own user model in Django, in which I want that my P.K  be the username field and not the id field autogenerated by Django?</p>
  
  <p>I am trying the following:</p>
  
  <p>I've create the userprofiles application in where I will create my customize django user model</p>
  
  <pre><code>INSTALLED_APPS = [
         ...
      'userprofiles.apps.UserprofilesConfig',
         ...
  ]
  
  AUTH_USER_MODEL = 'userprofiles.User'
  </code></pre>
  
  <p>In my <code>userprofiles/models.py</code> file I have defined the following:</p>
  
  <pre><code>from __future__ import unicode_literals
  from django.db import models
  from django.contrib.auth.models import AbstractBaseUser, UserManager, PermissionsMixin
  
  # Create your models here.
  class User(AbstractBaseUser, PermissionsMixin):
  
  GENDER_MALE = 'M'
  GENDER_FEMALE = 'F'
  GENDER_OTHER = 'O'
  GENDER_CHOICES = (
      (GENDER_MALE, u'Male'),
      (GENDER_FEMALE, u'Female'),
  )
  
  username = models.CharField(max_length=15, unique=True, db_index=True, primary_key=True)
  
  first_name=models.CharField(max_length=50, blank=False,)
  last_name=models.CharField(max_length=50, blank=False,)
  photo = models.ImageField(upload_to='avatars', blank=True)
  email = models.EmailField(max_length=254, unique=True)
  is_staff = models.BooleanField(
      default=True,
      help_text='Designates whether the user can log into this admin site.')
  is_active = models.BooleanField(default=True)
  #date_joined = models.DateTimeField(default=None)
  #date_joined = models.DateTimeField()
  
  gender = models.CharField(
      max_length=1,
      choices=GENDER_CHOICES,
      blank=False, )
  
  is_player = models.BooleanField(default=False)
  is_coach = models.BooleanField(default=False)
  is_viewer = models.BooleanField(default=False)
  
  USERNAME_FIELD = 'username'
  REQUIRED_FIELDS = ['email',]
  objects = UserManager()
  
  class Meta:
      db_table = 'auth_user'
  
  def get_full_name(self):
      """
      Returns the first_name plus the last_name, with a space in between.
      """
      full_name = '%s %s' % (self.first_name, self.last_name)
      return full_name.strip()
  
  def get_short_name(self):
      "Returns the short name for the user."
      return self.first_name
  </code></pre>
  
  <p>I am using the <a href="https://docs.djangoproject.com/en/dev/topics/auth/customizing/#specifying-a-custom-user-model" rel="nofollow noreferrer"><code>AbstractBaseUser</code> class</a> due to:</p>
  
  <blockquote>
    <p>AbstractBaseUser provides the core implementation of a User model,
    including hashed passwords and tokenized password resets. You must
    then provide some key implementation details: ...</p>
  </blockquote>
  
  <p>and also <a href="https://stackoverflow.com/questions/21514354/difference-between-abstractuser-and-abstractbaseuser-in-django">I considered this explanation</a> in which say that is necessary add manually the fields that I needed.</p>
  
  <p>Then, when I perform the migrations the fields that I've defined in my <code>User</code> model (that inherit from <code>AbstractBaseUser</code>) are created in my database:</p>
  
  <pre><code>(fuupbol) ➜  fuupbol_project git:(master) ✗ python manage.py makemigrations
      Migrations for 'userprofiles':
      0013_auto_20160418_2252.py:
      - Add field groups to user
      - Add field user_permissions to user
      - Alter field is_superuser on user
      (fuupbol) ➜  fuupbol_project git:(master) ✗ python manage.py migrate
      Operations to perform:
      Apply all migrations: sessions, userprofiles, admin, contenttypes, auth
      Running migrations:
      Rendering model states... DONE
       Applying userprofiles.0013_auto_20160418_2252... OK
      (fuupbol) ➜  fuupbol_project git:(master) ✗
  </code></pre>
  
  <p><a href="https://i.stack.imgur.com/rkwvs.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/rkwvs.jpg" alt="enter image description here"></a></p>
  
  <p>Then I've created a superuser via command line interface of this way:</p>
  
  <pre><code>(fuupbol) ➜  fuupbol_project git:(master) ✗ python manage.py createsuperuser
  Username: cdiaz   
  Email: cdiaz@fuupbol.org
  Password: 
  Password (again): 
  Superuser created successfully.
  (fuupbol) ➜  fuupbol_project git:(master) ✗ 
  </code></pre>
  
  <ul>
  <li>In addition, I add these fields of my custom User model for that Django Admin can view them, of this way:</li>
  </ul>
  
  <p>Like Django use special forms to create and edit forms in the admin relative to Users model, due to these was thinked only for the django original user model.</p>
  
  <p>Here  we are using a custom django user model with <code>AbstractBaseUser</code>, then we use the following class:</p>
  
  <ul>
  <li><code>UserChangeForm</code> which is applied to the User model, so this way is applied to the admin user form, and the <code>UserCreationForm</code> for that an user be created with from my user form customized with the previous modifications</li>
  </ul>
  
  <p>In my <code>userprofiles/forms.py</code> file</p>
  
  <pre><code>from django import forms
  from django.contrib.auth.forms import (UserChangeForm,UserCreationForm)
  
  from .models import User
  
  class CustomUserChangeForm(UserChangeForm):
      class Meta(UserChangeForm.Meta):
          model = User
  
  class CustomUserCreationForm(UserCreationForm):
      class Meta(UserCreationForm.Meta):
          model = User
  </code></pre>
  
  <p>In my <code>userprofiles/admin.py</code> file create an CustomUserAdmin class customized with the fields defined before in my custom User model</p>
  
  <pre><code>from django.contrib import admin                                                                                                                                                       
  from django.contrib.auth.admin import UserAdmin                                                                                                                                        
  
  from .models import User                                                                                                                                                               
  from .forms import CustomUserChangeForm, CustomUserCreationForm                                                                                                                        
  
  # Register your models here.                                                                                                                                                           
  
  class CustomUserAdmin(UserAdmin):                                                                                                                                                      
      form = CustomUserChangeForm                                                                                                                                                        
      add_form = CustomUserCreationForm                                                                                                                                                  
      fieldsets = UserAdmin.fieldsets + (                                                                                                                                                
          (                                                                                                                                                                              
              None, {                                                                                                                                                                    
                  'fields':(                                                                                                                                                             
                      'username',                                                   
                      'password',                                                                                                                                                        
                      'first_name',                                                                                                                                                      
                      'last_name',                                                                                                                                                       
                      'gender',                                                                                                                                                          
                      'email',                                                                                                                                                           
                      'photo',                                                                                                                                                           
                      'is_staff',                                                                                                                                                        
                      'is_active',                                                                                                                                                       
                      'is_superuser',                                                                                                                                                    
                      'is_player',                                                                                                                                                       
                      'is_coach',                                                                                                                                                        
                      'is_viewer',                                                                                                                                                       
                      'last_login',                                                                                                                                                                                                                                                                                                                           
                  )                                                                                                                                                                      
              }                                                                                                                                                                          
          ),                                                                                                                                                                             
      )                                                                                                                                                                                  
  
  
  #Change our UserAdmin class to inherit of our CustomUserAdmin created above (do not inherit of model.ModelAdmin)                                                                       
  @admin.register(User)                                                                                                                                                                  
  class UserAdmin(CustomUserAdmin):                                                                                                                                                                                            
      list_display = ('username','password','first_name','last_name','gender','email','photo','is_staff','is_active','is_superuser','is_player','is_coach','is_viewer','last_login',)  
  </code></pre>
  
  <p>Then when I go to the Django admin and I see the options to edit some user already created, I get this message:</p>
  
  <p><a href="https://i.stack.imgur.com/Ge7o6.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/Ge7o6.jpg" alt="enter image description here"></a></p>
  
  <p>In this moment I do not have the <code>date_joined</code> attribute in my User model, and if I add the <code>date_joined</code> attribute to my User model, and perform the migrations, I get this messages:</p>
  
  <pre><code>(fuupbol) ➜  fuupbol_project git:(master) ✗ python manage.py makemigrations userprofiles
  Migrations for 'userprofiles':
    0022_user_date_joined.py:
      - Add field date_joined to user
  (fuupbol) ➜  fuupbol_project git:(master) ✗ 
  </code></pre>
  
  <p>And when I execute the <code>migrate</code> command</p>
  
  <pre><code>(fuupbol) ➜  fuupbol_project git:(master) ✗ python manage.py migrate userprofiles       
      Operations to perform:
        Apply all migrations: userprofiles
      Running migrations:
        Rendering model states... DONE
        Applying userprofiles.0015_user_date_joined...Traceback (most recent call last):
        File "/home/bgarcial/.virtualenvs/fuupbol/lib/python3.4/site-packages/django/db/backends/utils.py", line 64, in execute
          return self.cursor.execute(sql, params)
      psycopg2.IntegrityError: column "date_joined" contains null values
  
  
      The above exception was the direct cause of the following exception:
  
      Traceback (most recent call last):
        File "manage.py", line 10, in &lt;module&gt;
          execute_from_command_line(sys.argv)
        File "/home/bgarcial/.virtualenvs/fuupbol/lib/python3.4/site-packages/django/core/management/__init__.py", line 353, in execute_from_command_line
          utility.execute()
        File "/home/bgarcial/.virtualenvs/fuupbol/lib/python3.4/site-packages/django/core/management/__init__.py", line 345, in execute
          self.fetch_command(subcommand).run_from_argv(self.argv)
        File "/home/bgarcial/.virtualenvs/fuupbol/lib/python3.4/site-packages/django/core/management/base.py", line 348, in run_from_argv
          self.execute(*args, **cmd_options)
        File "/home/bgarcial/.virtualenvs/fuupbol/lib/python3.4/site-packages/django/core/management/base.py", line 399, in execute
          output = self.handle(*args, **options)
        File "/home/bgarcial/.virtualenvs/fuupbol/lib/python3.4/site-packages/django/core/management/commands/migrate.py", line 200, in handle
          executor.migrate(targets, plan, fake=fake, fake_initial=fake_initial)
        File "/home/bgarcial/.virtualenvs/fuupbol/lib/python3.4/site-packages/django/db/migrations/executor.py", line 92, in migrate
          self._migrate_all_forwards(plan, full_plan, fake=fake, fake_initial=fake_initial)
        File "/home/bgarcial/.virtualenvs/fuupbol/lib/python3.4/site-packages/django/db/migrations/executor.py", line 121, in _migrate_all_forwards
          state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial)
        File "/home/bgarcial/.virtualenvs/fuupbol/lib/python3.4/site-packages/django/db/migrations/executor.py", line 198, in apply_migration
          state = migration.apply(state, schema_editor)
        File "/home/bgarcial/.virtualenvs/fuupbol/lib/python3.4/site-packages/django/db/migrations/migration.py", line 123, in apply
          operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
        File "/home/bgarcial/.virtualenvs/fuupbol/lib/python3.4/site-packages/django/db/migrations/operations/fields.py", line 62, in database_forwards
          field,
        File "/home/bgarcial/.virtualenvs/fuupbol/lib/python3.4/site-packages/django/db/backends/base/schema.py", line 396, in add_field
          self.execute(sql, params)
        File "/home/bgarcial/.virtualenvs/fuupbol/lib/python3.4/site-packages/django/db/backends/base/schema.py", line 110, in execute
          cursor.execute(sql, params)
        File "/home/bgarcial/.virtualenvs/fuupbol/lib/python3.4/site-packages/django/db/backends/utils.py", line 79, in execute
          return super(CursorDebugWrapper, self).execute(sql, params)
        File "/home/bgarcial/.virtualenvs/fuupbol/lib/python3.4/site-packages/django/db/backends/utils.py", line 64, in execute
          return self.cursor.execute(sql, params)
        File "/home/bgarcial/.virtualenvs/fuupbol/lib/python3.4/site-packages/django/db/utils.py", line 95, in __exit__
          six.reraise(dj_exc_type, dj_exc_value, traceback)
        File "/home/bgarcial/.virtualenvs/fuupbol/lib/python3.4/site-packages/django/utils/six.py", line 685, in reraise
          raise value.with_traceback(tb)
        File "/home/bgarcial/.virtualenvs/fuupbol/lib/python3.4/site-packages/django/db/backends/utils.py", line 64, in execute
          return self.cursor.execute(sql, params)
      django.db.utils.IntegrityError: column "date_joined" contains null values
  
      (fuupbol) ➜  fuupbol_project git:(master) ✗ 
  </code></pre>
  
  <p>I cannot understand the reason of the error message <code>django.db.utils.IntegrityError: column "date_joined" contains null values</code> due to in this moment I do not have this attribute <code>date_joined</code></p>
  
  <p>Any orientation would be appreciated. 
  Thanks</p>