<p>找到了一个解决方案:</p>
<pre><code>import operator
from functools import reduce
from django.contrib.admin import ListFilter, FieldListFilter
from django.db.models import Q
from django.contrib.admin.utils import (
get_fields_from_path, lookup_needs_distinct, prepare_lookup_value,
)
from django.http import QueryDict
class OrListFilter(ListFilter):
parameter_prefix = None
fields = None
def __init__(self, request, params, model, model_admin):
super(OrListFilter, self).__init__(
request, params, model, model_admin)
if self.parameter_prefix is None:
raise ImproperlyConfigured(
"The list filter '%s' does not specify "
"a 'parameter_prefix'." % self.__class__.__name__)
self.model_admin = model_admin
self.model = model
self.request = request
self.filter_specs = self.get_filters(request, {}, prefix=self.parameter_prefix+'-')
for p in self.expected_parameters():
if p in params:
value = params.pop(p)
field = p.split('-')[1]
self.used_parameters[field] = prepare_lookup_value(field, value)
def has_output(self):
return True
# see https://github.com/django/django/blob/1.8.5/django/contrib/admin/views/main.py#L104
def get_filters(self, request, params, prefix=''):
filter_specs = []
for field_path in self.fields:
field = get_fields_from_path(self.model, field_path)[-1]
field_list_filter_class = FieldListFilter.create
spec = field_list_filter_class(field, request, params,
self.model, self.model_admin, field_path=prefix + field_path)
# Check if we need to use distinct()
# use_distinct = (use_distinct or
# lookup_needs_distinct(self.lookup_opts,
# field_path))
filter_specs.append(spec)
return filter_specs
def expected_parameters(self):
parameters = []
for spec in self.filter_specs:
parameters += spec.expected_parameters()
return parameters
def choices(self, cl):
return []
def queryset(self, request, queryset):
origin_GET = request.GET.copy()
fake_GET = QueryDict(mutable=True)
fake_GET.update(self.used_parameters)
request.GET = fake_GET
all_params = {}
for spec in self.get_filters(request, self.used_parameters):
if spec and spec.has_output():
all_params.update(spec.used_parameters)
try:
query_params = [Q((key, value)) for key, value in all_params.items()]
queryset = queryset.filter(reduce(operator.or_, query_params))
except TypeError as e:
pass
# restore
request.GET = origin_GET
return queryset
class OrFilter(OrListFilter):
title = 'Or filter'
parameter_prefix = 'or1'
fields = ("foobar", "foofie")
class FooAdmin(admin.ModelAdmin):
list_filter = (OrFilter, )
</code></pre>
<p>应用程序名称/模板/管理/应用程序名称/更改_列表.html公司名称:</p>
^{pr2}$
<p>从@dima kudosh借了一些代码。在</p>
<h2>解释</h2>
<p><a href="https://github.com/django/django/blob/1.8.5/django/contrib/admin/views/main.py#L104" rel="nofollow">^{<cd1>}</a>从<code>ModelAdmin.list_filter</code>创建{<cd2>}s(筛选器规范),然后使用<a href="https://github.com/django/django/blob/1.8.5/django/contrib/admin/filters.py#L48" rel="nofollow">^{<cd4>}</a>到{a3}。在</p>
<p><a href="https://github.com/django/django/blob/1.8.5/django/contrib/admin/filters.py#L137" rel="nofollow">^{<cd6>}</a>使用<code>used_parameters</code>过滤查询集:<code>queryset.filter(**self.used_parameters)</code>。在</p>
<p>因此,我们可以从<code>OrListFilter.fields</code>创建<code>FieldListFilter</code>,并使用它们的<code>used_parameters</code>构造<strong>或</strong>查询:</p>
<pre><code>all_params = {}
for spec in self.get_filters(request, self.used_parameters):
if spec and spec.has_output():
all_params.update(spec.used_parameters)
try:
query_params = [Q((key, value)) for key, value in all_params.items()]
queryset = queryset.filter(reduce(operator.or_, query_params))
except TypeError as e:
pass
</code></pre>