В джанговской админке есть встроенный механизм поиска по полям модели. Достаточно просто указать поле search_fields
в классе, унаследованном от ModelAdmin
, и поиск по нужным полям заработает сам. Однако, иногда возникают задачи обеспечить поиск не только по простым полям, но и по значениям, сгенерированным методами. Это тоже возможно.
В моём случае на сайте, посвящённом поиску работы, структура данных такова:
class Company(models.Mode):
…
personal_number = models.CharField(max_length=11)
class Vacancy(models.Model):
…
owner = models.ForeignKey(Company)
personal_number = models.PositiveIntegerField()
def get_personal_number(self):
return "{}-{}".format(self.owner.personal_number, self.personal_number)
И вот это этому значению, генерируемому методом get_personal_number
, нужен поиск в админке, в кабинете модератора, который делается отдельно от админки, а возможно в будущем заказчик пожелает сделать поиск по этому значению и в публичной части.
Имя метода в search_fields
не указать, нужно немного поколдовать.
Поскольку действия над моделью нужно будет выполнять в нескольких местах, логично саму логику поиска записать в менеджере модели.
import re
class VacancyManager(models.Manager):
def filter_by_personal_number(self, personal_number):
m = re.match(r"(?P<company_number>.{2}\d+)-(?P<vacancy_number>\d+)", personal_number)
if m:
return self.get_queryset().filter(
personal_number=int(m.group(vacancy_number)),
owner__personal_number=m.group('company_number')
)
else:
return self.none()
В приведённом коде присутствует некоторая специфика проекта: регулярным выражением проверяется соответствие формату номера. В вашем случае эта часть может быть совершенно другой.
Теперь в админке следует дописать логику поиска:
class VacancyAdmin(admin.ModelAdmin):
def get_search_results(self, request, queryset, search_term):
queryset, use_distinct = super().get_search_results(request, queryset, search_term)
queryset |= self.model.objects.filter_by_personal_number(search_term)
return queryset, use_distinct
метод get_search_results
класса ModelAdmin
как раз и отвечает за логику поиска. Возьмём штатный метод поиска, чтобы оставить себе возможность использовать поле search_fields
, добавим выборку из модели свеженаписанным менеджером, и получим прекрасно работающий поиск по вычисляемому полю с возможностью использовать этот же алгоритм где угодно в проекте.
Пример результата(используется Django Grappelli)