Query Django Users by get_username method
I am trying to get the Django User object with a specific username. The obvious way to do it is like this:
from django.contrib.auth.models import User
bob = User.objects.get(username="Bob")
But I noticed that User objects have a get_username() method which states that
you should use this method instead of referencing the username attribute directly.
This makes me wary of using the attribute in queries.
Is there a way to query User objects by this method instead of by the username attribute? I'm looking for a more elegant, queryset-oriented version of this:
bob = [u for u in User.objects.all() if u.get_username() == "Bob"][0]
if such a thing exists.
If you want to retrieve a user instance from the database, the preferred way is to either use the get or get_object_or_404 method.
User.objects.get(username="Bob")
B
The two methods serve different purposes: The get_username() method returns the username for the currently logged-in user. You should not use this to retrieve the records of a random user. Also note that this method returns the record used as USERNAME_FIELD which can be a username, an email or any other unique identifier because Django User model can be swapped out.
The get() method on the other hand retrieves the model instance that is being requested. You can use this if you want to get a user instance using the username. Ensure to handle the DoesNotExist Exception if the object doesn't exist and the MultipleObjectsReturned if your username field is not unique:
try:
User.objects.get(username="Bob")
except User.DoesNotExist:
...
except MultipleObjectsReturned:
...
Or you can also use the get_object_or_404 method
You can’t use get_username() in a queryset - it’s just a Python method, not a database field.
For lookups, you must query by the actual field name:
bob = User.objects.get(username="Bob")
If you really want a method-based approach, you can define your own model method or manager method, for example:
class CustomUserManager(models.Manager):
def get_by_username(self, username):
return self.get(username=username)
class User(AbstractUser):
objects = CustomUserManager()
then you can use like this:
bob = User.objects.get_by_username("Bob")
This makes me wary of using the attribute in queries.
You are not really using attributes in a query. You are only using attributes from the class that are subclasses of django.db.models.fields.Field. So you can not filter with an arbitrary attribute, or method.
Luckily, if we look at the source code of .get_username(…) [GitHub], it says:
def get_username(self): """Return the username for this User.""" return getattr(self, self.USERNAME_FIELD)
this is used for example if you want to use the email field instead of username, or when make a custom user model with another field.
We can then make the query with:
from django.contrib.auth.models import User
bob = User.objects.get(**{User.USERNAME_FIELD: 'Bob'})