title: Django username field nullable breaks default auth backend
body: <p>when using a custom User model, extending <code>AbstractBaseUser</code>, I've run into a problem when the USERNAME_FIELD points to a nullable field</p>
  
  <p>what I'm trying to accomplish is to allow multiple methods of login (facebook, username) and for that I have two unique identifier fields (facebook_id, username) but both have to be nullable because an account doesn't have to have both (and most accounts won't have both)</p>
  
  <p>so for logging in with username, I rely on Django's built in login auth backend</p>
  
  <p>where it falls apart is when trying to log in with an alternative login method (facebook) and the Django auth is attempted first</p>
  
  <pre><code>class ModelBackend(object):
      """
      Authenticates against settings.AUTH_USER_MODEL.
      """
  
      def authenticate(self, username=None, password=None, **kwargs):
          UserModel = get_user_model()
          if username is None:
              username = kwargs.get(UserModel.USERNAME_FIELD)
          try:
              user = UserModel._default_manager.get_by_natural_key(username)
              if user.check_password(password):
                  return user
          except UserModel.DoesNotExist:
              # Run the default password hasher once to reduce the timing
              # difference between an existing and a non-existing user (#20760).
              UserModel().set_password(password)
  </code></pre>
  
  <p>the <code>if username is None</code> hack is meant to fix the situation where the username field isn't actually called "username" so the <code>username</code> parameter is empty but the actual provided username can be found in <code>kwargs</code></p>
  
  <p>the issue is that it ends up with None value anyway (because kwargs contains facebook_id=12345) and ends up passing that to <code>get_by_natural_key</code></p>
  
  <pre><code>def get_by_natural_key(self, username):
      return self.get(**{self.model.USERNAME_FIELD: username})
  </code></pre>
  
  <p>which translates roughly to <code>User.objects.get(username=None)</code></p>
  
  <p>since my username field is nullable, this returns multiple results, the whole thing throws an models.MultipleObjectsReturned exception ("get() returned more than one User -- it returned 417!") and prevents any other auth backends from running</p>
  
  <p>from my perspective there's several issues:</p>
  
  <ol>
  <li>ModelBackend shouldn't be just blindly attempting to retrieve a user if its attempts at figuring out the provided username result with <code>None</code></li>
  <li>get_by_natural_key should catch the MultipleObjectsReturned and gracefully fail, or authenticate() should handle that scenario and fail to log the user in, instead of bombing the entire auth mechanism</li>
  </ol>
  
  <p>known workarounds:</p>
  
  <p>I know I can move the ModelBackend to be the last method attempted but that just makes the dumb query run sometimes instead of always, I'd rather fix it so it never does. I'm also slightly concerned with its performance as number of username=None users grows</p>
  
  <p>I also know I can extend ModelBackend, patch the holes and just not use the stock ModelBackend, but I don't know if there are any gotchas to that approach... are existing sessions using ModelBackend lost?</p>
  
  <p>For simplification purposes, I skipped the part where I actually use a nullable email field as the username :D and I know that for that I could just easily use a custom auth backend but once I got nullable-email-field-login working I started thinking I can probably save myself some headache in generating usernames for users coming from facebook (and letting them choose an unused username later on in the process) by making username field nullable as well :D</p>
  
  <p>I'm concerned that having a nullable USERNAME_FIELD is going to make Django fail in various different ways, and I saw no warning for this or explanation for why. It's silly that a system that supports multiple login schemes cannot survive it's stock auth identifier being empty.</p>