发布于 2019-04-02 20:58:58
你有没有困难的财产?如果没有,您可以将其重写为queryset,如下所示:
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)也许它不是你想要的,但在某些情况下它可以帮助你。
发布于 2019-04-02 20:55:27
django-filter希望并假设您使用的是querysets。一旦您获取一个查询集并将其更改为list,那么下游的任何东西都需要能够处理list或者只是遍历列表,它不再是一个查询集。
如果你有一个django_filters.FilterSet例如:
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例如:
class MyPropertyFilter(django_filters.Filter):
def filter(self, qs, value):
return [row for row in qs if row.baz == value]在这一点上,任何下游的MyProperteyFilter会有一个列表。
注:我相信fields应该有你的自定义过滤器,MyPropertyFilter最后,因为它总是在正常的查询集过滤器之后被处理。
——————————————————————————————————————
因此,您刚刚破坏了"queryset“API,对于某些值而言,就是broken。在这一点上,您将不得不解决下游的任何错误。如果在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你在一个未知的领域,你必须破解一条路。
不管怎么说,我以前也这么做过,这并不可怕。只需接受错误发生时的错误即可。
发布于 2020-09-09 22:00:16
由于按非字段属性进行过滤,例如property不可避免地将QuerySet至list(或类似的),我喜欢推迟它,并在上面做过滤object_list在get_context_data方法。将过滤逻辑保留在filterset类中,我使用了一个简单的技巧。我定义了一个decorator
def attr_filter(func):
def wrapper(self, queryset, name, value, force=False, *args, **kwargs):
if force:
return func(self, queryset, name, value, *args, **kwargs)
else:
return queryset
return wrapper它用于django-filter非字段过滤方法。多亏了这个装饰器,过滤基本上不做(或跳过)非字段过滤方法(因为force=False默认值)。
接下来,我定义了一个Mixin将在view类。
class FilterByAttrsMixin:
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
filtered_list = self.filter_qs_by_attributes(self.object_list, self.filterset)
context.update({
'object_list': filtered_list,
})
return context
def filter_qs_by_attributes(self, queryset, filterset_instance):
if hasattr(filterset_instance.form, 'cleaned_data'):
for field_name in filter_instance.filters:
method_name = f'attr_filter_{field_name}'
if hasattr(filterset_instance, method_name):
value = filterset_instance.form.cleaned_data[field_name]
if value:
queryset = getattr(filterset_instance, filter_method_name)(queryset, field_name, value, force=True)
return queryset它基本上只是返回到你的filterset并运行所有调用attr_filter_,这一次使用force=True。
总之,您需要:
FilterByAttrsMixin在您的view类attr_filter_attr_filter过滤方法上的装饰器简单的例子(鉴于我有model被称为MyModel使用property被称为is_static我想通过以下方式进行过滤:
型号:
class MyModel(models.Model):
...
@property
def is_static(self):
...查看:
class MyFilterView(FilterByAttrsMixin, django_filters.views.FilterView):
...
filterset_class = MyFiltersetClass
...过滤器:
class MyFiltersetClass(django_filters.FilterSet):
is_static = django_filters.BooleanFilter(
method='attr_filter_is_static',
)
class Meta:
model = MyModel
fields = [...]
@attr_filter
def attr_filter_is_static(self, queryset, name, value):
return [instance for instance in queryset if instance.is_static]https://stackoverflow.com/questions/55474992
复制相似问题