Django. Кастомный QuerySet и Manager для добавления в цепь вызова дополнительных методов
Иногда необходимо добавить в цепь вызова кастомные методы для QuerySet, но если определить просто свой менеджер модели, то этого оказывается недостаточно, потому что он действует только как точка доступа к QuerySet.
Пример использования менеджера модели без цепи вызовов:
from django.db import models class CustomManager(models.Manager): def custom_filter(self, **kwargs): kwargs['status'] = 'published' return super(CustomManager, self).get_query_set().filter(**kwargs) def custom_order_by(self, *args): args = ('published', ) + args return super(CustomManager, self).get_query_set().order_by(*args) class MyModel(models.Model): ... custom_manager = CustomManager()
Далее вы вызываете его так:
MyModel.custom_manager.custom_filter(something=42) # или так MyModel.custom_manager.custom_order_by('some_field')
Но если вы хотите использовать в цепи вызовов, то ничего не выйдет, так как в вашем "custom_filter" вы возвращаете models.query.QuerySet и связь с менеджером на этом заканчивается:
# Так уже сделать не получится: MyModel.custom_manager.custom_filter(something=42).custom_order_by('some_field')
Чтобы исправить эту ситуацию необходимо определить свой QuerySet и в нём уже определять свои методы, а не в менеджере. А в самом менеджере только определить "get_query_set", который будет возвращать методы вашего CustomQuerySet:
from django.db import models class CustomQuerySet(models.query.QuerySet): """Substitution the QuerySet, and adding additional methods to QuerySet """ def custom_filter(self, **kwargs): kwargs['status'] = "published" return self.filter(**kwargs) def custom_order_by(self, *args): args = ('published', ) + args return self.order_by(*args) class CustomManager(models.Manager): def get_query_set(self): model = models.get_model(self.model._meta.app_label, self.model._meta.object_name) return CustomQuerySet(model) def __getattr__(self, attr, *args): try: return getattr(self.__class__, attr, *args) except AttributeError: return getattr(self.get_query_set(), attr, *args)
В коде проекта просто используйте CustomManager или наследуйте свои менеджеры от него, чтобы добавить ваши дополнительные методы из CustomQuerySet:
class MyModel(models.Model): ... custom_manager = CustomManager() MyModel.custom_manager.custom_filter(something=42).custom_order_by('some_field')
Так, например, у меня сделан поиск в Marcus. Правда сам поиск пока временный (через "LIKE"), потом хочу сделать возможность передавать свои методы поиска, например "MATCH/AGAINST" или "SphinxSearch".
По мотивам
38177714.9958222.1347833143.c8f1dc4a1b410c2ad13b0ef9e4f3d2f4
Комментарии
Стоит взглянуть на это решение https://bitbucket.org/carljm/django-model-utils/src
Оставьте свой комментарий