title: Can't login to Django Admin with custom user and Mezzanine/South
body: <p>I have django app with a custom user like this:</p>
  
  <pre><code>import ...
  
  logger = logging.getLogger(__name__)
  
  
  # # Person (representation of people)
  
  
  class AbstractPerson(models.Model):
      """
      ABSTRACT model representing basic information about a person on the platform,
      be it a user or a person used in acts he's generating.
      """
  
      MALE = 'M'
      FEMALE = 'F'
      GIRL = 'G'
      FRENCH_TITLES = (
          (MALE, 'M.'),
          (FEMALE, 'Mme'),
          (GIRL, 'Mlle'),
      )
  
      date_created = models.DateTimeField(_('date created'),
                                          default=timezone.now,
                                          db_index=True)
  
      title = models.CharField(u'Civilité', max_length=1,
                               choices=FRENCH_TITLES,
                               blank=True)
      first_name = models.CharField(u'Prénom', max_length=500, blank=True)
      last_name = models.CharField(u'Nom', max_length=500, blank=True,
                                   db_index=True)
      phone = models.CharField(u'Téléphone', max_length=10, blank=True)
      address_1 = models.CharField(u'Adresse', max_length=200, blank=True)
      address_2 = models.CharField(u"Complément d'adresse", max_length=200,
                                   blank=True, null=True)
      zipcode = models.CharField(u'Code Postal', max_length=10, blank=True)
      city = models.CharField(u'Ville', max_length=50, blank=True)
  
  
      class Meta:
          abstract = True
  
  
  # # Auth
  
  class UserManager(BaseUserManager):
      """Replacement for django auth's UserManager"""
  
      def create_user(self, email, password=None, **extra_fields):
          """
          Creates and saves a User with the given email and password.
          """
          if not email:
              raise ValueError('Users must have an email address')
          email = UserManager.normalize_email(email)
  
          now = timezone.now()
  
          user = self.model(email=email,
                            is_staff=False, is_active=True, is_superuser=False,
                            last_login=now, date_created=now, **extra_fields)
  
          user.set_password(password)
          user.save(using=self._db)
          return user
  
      def create_superuser(self, email, password, **extra_fields):
          u = self.create_user(email, password=password, **extra_fields)
          u.is_staff = True
          u.is_active = True
          u.is_superuser = True
          u.save(using=self._db)
          return u
  
  
  class User(AbstractPerson, AbstractBaseUser, PermissionsMixin):
      """
      Replacement for django.contrib.auth's User.
      Gets basic Person information injected from AbstractPerson
      """
  
      # Regular fields
      email = models.EmailField(_('email address'), max_length=255,
                                unique=True, db_index=True)
      is_staff = models.BooleanField(_('staff status'), default=False,
                                     help_text=_('Designates whether the user '
                                                 'can log into this admin site.'))
      is_active = models.BooleanField(_('active'), default=True,
                                      help_text=_('Designates whether the user '
                                                  'should be treated as active. '
                                                  'Unselect this instead of '
                                                  'deleting accounts.'))
  
      # Compatibility with Mezzanine accounts app
      username = models.EmailField(_('username (copy of email address)'),
                                   max_length=255,
                                   unique=True, db_index=True)
  
      objects = UserManager()
  
      USERNAME_FIELD = 'email'
      REQUIRED_FIELDS = []  # Nothing required apart from email
  
  
      class Meta:
          verbose_name = _('user')
          verbose_name_plural = _('users')
      abstract = False
  
      def save(self, *args, **kwargs):
          self.username = self.email
          try: kwargs.pop('username')
          except KeyError: pass
          super(User, self).save(*args, **kwargs)
  </code></pre>
  
  <p>Then my settings are:</p>
  
  <pre><code># Custom user model
  AUTH_USER_MODEL = 'useraccount.User'
  
  INSTALLED_APPS = (
      'grappelli',
      'django.contrib.admin',
      'django.contrib.auth',
      'django.contrib.comments',
      'django.contrib.contenttypes',
      "django.contrib.redirects",
      'django.contrib.sessions',
      "django.contrib.sites",
      "django.contrib.sitemaps",
      'django.contrib.staticfiles',
      "storages",          # django-storages backend
      ## Custom user model and such
      'useraccount',
      ## Mezzanine
      "mezzanine.boot",
      "mezzanine.conf",
      "mezzanine.core",
      "mezzanine.generic",
      #"mezzanine.blog",
      "mezzanine.forms",
      "mezzanine.pages",
      #"mezzanine.galleries",
      #"mezzanine.twitter",
      #"mezzanine.accounts",
      #"mezzanine.mobile",
      'south',
  )
  
  MIDDLEWARE_CLASSES = (
      'django.contrib.sessions.middleware.SessionMiddleware',
      'django.middleware.common.CommonMiddleware',
      'django.middleware.csrf.CsrfViewMiddleware',
      'django.contrib.auth.middleware.AuthenticationMiddleware',
      'django.contrib.messages.middleware.MessageMiddleware',
      'django.middleware.clickjacking.XFrameOptionsMiddleware',
      "mezzanine.core.request.CurrentRequestMiddleware",
      "mezzanine.core.middleware.RedirectFallbackMiddleware",
      "mezzanine.core.middleware.TemplateForDeviceMiddleware",
      "mezzanine.core.middleware.TemplateForHostMiddleware",
      "mezzanine.core.middleware.AdminLoginInterfaceSelectorMiddleware",
      "mezzanine.core.middleware.SitePermissionMiddleware",
      # Uncomment the following if using any of the SSL settings:
      #"mezzanine.core.middleware.SSLRedirectMiddleware",
      "mezzanine.pages.middleware.PageMiddleware",
      "mezzanine.core.middleware.FetchFromCacheMiddleware",
  )
  </code></pre>
  
  <p>So now with that, I've synced the db and created a superuser. In the shell, everything look good:</p>
  
  <pre><code>In [1]: from useraccount.models import User
  
  In [2]: from django.contrib.auth import authenticate
  
  In [3]: authenticate(username='john', password='secret')
  Out[3]: &lt;User: john&gt;
  
  In [4]: u = User.objects.all()[0]
  
  In [5]: u.is_active
  Out[5]: True
  
  In [6]: u.is_staff
  Out[6]: True
  
  In [7]: u.is_superuser
  Out[7]: True
  </code></pre>
  
  <p>And with all that, impossible to connect to the admin... Admin doesn't say: 
      <code>Please enter the correct email address and password for a staff account. Note that both fields may be case-sensitive.</code> </p>
  
  <p>But:
      <code>Please correct the error below.</code></p>
  
  <p>Any idea?</p>
  
  <p><strong>EDIT</strong></p>
  
  <p>Sorry, I didn't precised that I used MezzanineBackend to authenticate the user: </p>
  
  <p><code>AUTHENTICATION_BACKENDS = ("mezzanine.core.auth_backends.MezzanineBackend",)</code></p>
  
  <p>The code is this:</p>
  
  <pre><code>class MezzanineBackend(ModelBackend):
  
  def authenticate(self, **kwargs):
      if kwargs:
          username = kwargs.pop("username", None)
          if username:
              username_or_email = Q(username=username) | Q(email=username)
              password = kwargs.pop("password", None)
              try:
                  user = User.objects.get(username_or_email, **kwargs)
              except User.DoesNotExist:
                  pass
              else:
                  if user.check_password(password):
                      return user
          else:
              if 'uidb36' not in kwargs:
                  return
              kwargs["id"] = base36_to_int(kwargs.pop("uidb36"))
              token = kwargs.pop("token")
              try:
                  user = User.objects.get(**kwargs)
              except User.DoesNotExist:
                  pass
              else:
                  if default_token_generator.check_token(user, token):
                      return user
  </code></pre>
  
  <p>Maybe the problem is that there is no get_user method, so I'll try this and come back if it doesn't work</p>
  
  <p><strong>EDIT2</strong></p>
  
  <p>No changes with the get_user method added... Any ideas?</p>