Запрашивайте пользователей Django методом get_username

Я пытаюсь получить объект Django User с определенным именем пользователя. Очевидный способ сделать это такой:

from django.contrib.auth.models import User
bob = User.objects.get(username="Bob")

Но я заметил, что у пользовательских объектов есть метод get_username(), который утверждает, что

вам следует использовать этот метод вместо прямой ссылки на атрибут username.

Это заставляет меня опасаться использования атрибута в запросах.

Есть ли способ запрашивать пользовательские объекты с помощью этого метода, а не с помощью атрибута username? Я ищу более элегантную версию, ориентированную на набор запросов:

bob = [u for u in User.objects.all() if u.get_username() == "Bob"][0]

если такое вообще существует.

Если вы хотите получить экземпляр пользователя из базы данных, предпочтительным способом является использование метода get или get_object_or_404.

User.objects.get(имя пользователя="Bob")

B

Эти два метода служат разным целям: метод get_username() возвращает имя пользователя, который в данный момент вошел в систему. Не следует использовать его для получения записей о случайном пользователе. Также обратите внимание, что этот метод возвращает запись, используемую в качестве USERNAME_FIELD, которая может быть именем пользователя, адресом электронной почты или любым другим уникальным идентификатором, поскольку пользовательская модель Django может быть заменена.

Метод get(), с другой стороны, извлекает запрашиваемый экземпляр модели. Вы можете использовать его, если хотите получить экземпляр пользователя, используя имя пользователя. Убедитесь, что обработано исключение DoesNotExist, если объект не существует, и возвращено несколько объектов, если ваше поле username не уникально:

попробуйте:

User.objects.get(username="Bob")

кроме User.Не существует:

...

кроме нескольких возвращенных объектов:

...

Или вы также можете использовать метод get_object_or_404

Вы не можете использовать get_username() в наборе запросов - это просто метод Python, а не поле базы данных.
Для поиска вы должны выполнить запрос по фактическому имени поля:

bob = User.objects.get(username="Bob")

Если вам действительно нужен подход, основанный на методе, вы можете определить свой собственный метод моделирования или метод менеджера, например:

class CustomUserManager(models.Manager):
    def get_by_username(self, username):
        return self.get(username=username)

class User(AbstractUser):
    objects = CustomUserManager()

тогда вы можете использовать вот так:


bob = User.objects.get_by_username("Bob")

Это заставляет меня опасаться использования атрибута в запросах.

На самом деле вы не используете атрибуты в запросе. Вы используете только атрибуты из класса, которые являются подклассами django.db.models.fields.Field. Таким образом, вы не можете выполнять фильтрацию с помощью произвольного атрибута или метода.

К счастью, если мы посмотрим на исходный код .get_username(…) [GitHub], там будет написано:

def get_username(self):
    """Return the username for this User."""
    return getattr(self, self.USERNAME_FIELD)

это используется, например, если вы хотите использовать поле email вместо username, или при создании пользовательской модели пользователя с другим полем.

Затем мы можем задать запрос с помощью:

from django.contrib.auth.models import User

bob = User.objects.get(**{User.USERNAME_FIELD: 'Bob'})
Вернуться на верх