Django-фильтр: фильтрация по свойству модели - PullRequest
1 голос
/ 02 апреля 2019

Я прочитал на нескольких местах , что невозможно фильтровать наборы запросов Django, используя свойства, потому что Django ORM не будет знать, как преобразовать их в SQL.

Однако, как только данные извлекаются и загружаются в память, должно быть в состоянии фильтровать их в Python, используя эти свойства.

И мой вопрос: есть ли какая-либо библиотека, которая разрешает наборы запросовфильтроваться по свойствам в памяти?И если нет, то каким образом должны быть подделаны наборы запросов, чтобы это стало возможным?И как включить django-filter в это?

Ответы [ 2 ]

1 голос
/ 02 апреля 2019

У вас сложная собственность или нет? Если нет, вы можете переписать его в набор запросов следующим образом:

from django.db import models

class UserQueryset(models.Manager):

    def get_queryset(self):

        return super().get_queryset().annotate(
            has_profile=models.Exists(Profile.objects.filter(user_id=models.OuterRef('id')))
        )

class User(models.Model):
    objects = UserQueryset


class Profile(models.Model):
    user = models.OneToOneField(User, related_name='profile')


# When you want to filter by has profile just use it like has field has profile

user_with_profiles = User.objects.filter(has_profile=True)

Может быть, это не то, что вы хотите, но это может помочь вам в некоторых случаях

1 голос
/ 02 апреля 2019

django-filter хочет и предполагает, что вы используете наборы запросов.Как только вы берете набор запросов и изменяете его на list, то все, что находится в нисходящем направлении, должно иметь возможность обрабатывать только list или просто выполнять итерацию по списку, который больше не является набором запросов.

Еслиу вас есть django_filters.FilterSet like:

class FooFilterset(django_filters.FilterSet):
    bar = django_filters.Filter('updated', lookup_expr='exact')
    my_property_filter = MyPropertyFilter('property')
    class Meta:
        model = Foo
        fields = ('bar',  'my_property_filter')

, тогда вы можете написать MyPropertyFilter like:

class MyPropertyFilter(django_filters.Filter):
    def filter(self, qs, value):
        return [row for row in qs if row.baz == value]

На этом этапе все, что ниже MyProperteyFilter будет иметь список.

Примечание. Я полагаю, что порядок fields должен иметь ваш собственный фильтр, MyPropertyFilter последний, потому что тогда он всегда будет обрабатываться после обычных фильтров набора запросов.


Итак, вы только что нарушили API "queryset", для определенных значений не работает.На этом этапе вам придется работать с ошибками всего, что находится ниже по течению.Если что-то после FilterSet требует .count участника, вы можете изменить MyPropertyFilter, например:

class MyPropertyFilter(django_filters.Filter):
    def filter(self, qs, value):
        result = [row for row in qs if row.baz == value]
        result.count = len(result)
        return result

Вы находитесь на неизведанной территории, и вам придется взломать свой путь.

В любом случае, я делал это раньше, и это не ужасно.Просто примите ошибки по мере их поступления.

...