Django models: возможно ли принудительное использование иконок в filter/get для определенного поля с помощью менеджера?

Допустим, у меня есть модель со строковым полем, подобным этому

class Product(models.Model):
    upc = models.CharField(max_length=12, blank=False, null=False)

Возможно ли создать менеджер моделей или что-то подобное, где каждый раз, когда я использую Product.objects.get/Product.objects.filter, он переопределяет поиск по умолчанию, чтобы заставить поиск/фильтр вести себя так, как я использовал icontains?

Как в:

Product.objects.get(upc="012345678902")
Product.objects.filter(upc="012345678902")

По умолчанию будет вести себя следующим образом:

Product.objects.get(upc__icontains="012345678902")
Product.objects.filter(upc__icontains="012345678902")

Вы можете настроить менеджер запросов или набор запросов и переопределить метод get/filter. Демонстрация ниже расскажет вам, как настроить менеджер запросов, реализующий force icontains.

from django.db import models


class ForceIContainsManager(models.Manager):
    force_icontains_fields = None

    def __init__(self, *args, **kwargs) -> None:
        if "force_icontains_fields" in kwargs:
            self.force_icontains_fields = kwargs.pop("force_icontains_fields")
        super(ForceIContainsManager, self).__init__(*args, **kwargs)

    def get(self, *args, **kwargs):
        kwargs = self._force_icontains(**kwargs)
        return super(ForceIContainsManager, self).get(*args, **kwargs)

    def filter(self, *args, **kwargs):
        kwargs = self._force_icontains(**kwargs)
        return super(ForceIContainsManager, self).filter(*args, **kwargs)

    def _force_icontains(self, **kwargs):
        """
        replace field in force_icontains_fields to icontains style
        """
        if not self.force_icontains_fields:
            return kwargs
        for field in self.force_icontains_fields:
            if field in kwargs:
                v = kwargs.pop(field)
                new_field_name = '%s__icontains' % field
                kwargs[new_field_name] = v
        return kwargs


class YourModel(models.Model):
    # define a another manager, YourModel.manager will force icontains on certain fields
    manager = ForceIContainsManager(
        force_icontains_fields=["field1", "field2"])
    # if you want use YourModel.objects, you should uncomment below
    # objects = ForceIContainsManager(force_icontains_fields=["field1", "field2"])
    pass


# check sql
print(YourModel.manager.filter(field1='test').query)

Больше настроек можно увидеть https://sodocumentation.net/django/topic/1400/custom-managers-and-querysets

QueryManager проксирует все методы в QuerySet на BaseManager.from_queryset, достаточно выбрать один.

Вернуться на верх