#django #django-models #django-orm
Вопрос:
Абстрактпользователь Django имеет поля для first_name
и last_name
, и get_full_name
метод.
Если бы я хотел отфильтровать пользователей на основе поиска их полного имени, я могу добавить пользовательский менеджер моделей для Пользователя, у которого есть метод примерно такой:
def filter(self, *args, **kwargs):
queryset = super().get_queryset()
if any(key for key in kwargs if key.startswith('full_name')):
queryset = queryset.annotate(
full_name=Concat(models.F('first_name'), models.Value(' '), models.F('last_name'))
)
return queryset.filter(*args, **kwargs)
Это значит, что я могу делать такие вещи, как:
User.objects.filter(full_name='Foo Bar')
User.objects.filter(full_name__icontains='foo b')
... etc
Но, конечно, это будет работать только при прямой фильтрации пользователей выше. Если у вас есть объекты Post, которые принадлежат пользователю, вы получите это:
Post.objects.filter(user__full_name='Foo Bar')
...
FieldError: Related Field got invalid lookup: full_name
Итак, вопрос в том, есть ли способ (без изменения всех моделей для создания пользовательских менеджеров), чтобы Django всегда распознавал данный термин (в данном случае «полное имя») во всех соединениях с таблицей данной модели и аннотировал необходимое значение, чтобы его можно было отфильтровать?
Примечание: Я знаю, что, конечно, мог бы добавить full_name
в качестве поля пользователя и попытаться убедиться, что оно всегда актуально, но я специально стараюсь не добавлять эти денормализованные данные в базу данных.
Комментарии:
1. Похоже, что это невозможно отсюда
2. В частности, это заявление:
Base managers aren’t used when querying on related models, or when accessing a one-to-many or many-to-many relationship. For example, if the Question model from the tutorial had a deleted field and a base manager that filters out instances with deleted=True, a queryset like Choice.objects.filter(question__name__startswith='What') would include choices related to deleted questions.
3. Вы, вероятно, могли бы просто сделать что-то вроде
Post.objects.filter(user__in=filtered_and_annotated_user_queryset)