【问题标题】:Custom Filter in Django Admin returns SuspiciousOperationDjango Admin 中的自定义过滤器返回 SuspiciousOperation
【发布时间】:2013-07-01 16:42:30
【问题描述】:

我正在尝试实现this snippet 的新版本,使其与 Django 1.4 和 1.5 兼容

已经发展了很多,下面的代码几乎可以正常工作,只是 Django 向我返回了一个 SuspiciousOperation 错误。我知道如何破解它,但我不想触及 Django 的核心。如果您有什么建议,欢迎:

这是我的过滤器:

class RelatedNullFilterSpec(FieldListFilter):
    def __init__(self, field, request, params, model, model_admin, field_path):
        field_root, field_name = field_path.rsplit('__', 1)
        self.lookup_title = field.verbose_name
        self.title = self.lookup_title
        self.null_lookup_kwarg = '%s__isnull' % field_root
        self.null_lookup_val = request.GET.get(self.null_lookup_kwarg, None)
        self.lookup_kwarg = '%s__exact' % (field_path)
        self.lookup_val = request.GET.get(self.lookup_kwarg, None)
        if isinstance(field, models.fields.BooleanField):
            self.lookup_choices = (
                # (None, _('All')),
                ('1', _('Yes')),
                ('0', _('No')))
        else:
            self.lookup_choices = field.get_choices(include_blank=False)
        super(RelatedNullFilterSpec, self).__init__(field, request, params, model, model_admin, field_path)

    def expected_parameters(self):
        return [self.lookup_kwarg, self.null_lookup_kwarg]

    def choices(self, cl):
        yield {'selected': self.lookup_val is None and self.null_lookup_val is None,
               'query_string': cl.get_query_string({}, [self.lookup_kwarg,self.null_lookup_kwarg]),
               'display': _('All')}
        yield {'selected': self.lookup_val is None and self.null_lookup_val=="True",
               'query_string': cl.get_query_string({self.null_lookup_kwarg:True},[self.lookup_kwarg]),
               'display': _('Null')}
        yield {'selected': self.lookup_val is None and self.null_lookup_val=="False",
               'query_string': cl.get_query_string({self.null_lookup_kwarg:False},[self.lookup_kwarg]),
               'display': _('Not Null')}
        for pk_val, val in self.lookup_choices:
            yield {'selected': self.lookup_val == smart_unicode(pk_val),
                   'query_string': cl.get_query_string({self.lookup_kwarg: pk_val},[self.null_lookup_kwarg]),
                   'display': val}

然后在我的管理员中,我有以下内容:

list_filter = ('time_added', 'time_modified', ('model1__model2__property', RelatedNullFilterSpec),)

我总是从 Django BaseModelAdmin 类的lookup_allowed 方法中得到这个错误...

在 django.db.models.options 中,我可以实现一个 hack 来覆盖或扩展 self.related_fkey_lookups,但这对我来说有点太老套了。

编辑:请注意,以下几乎标准的过滤器也返回相同的错误:('venue__eat_venue', BooleanFieldListFilter)

一般来说,我的目标是我想要一个过滤器,它允许我通过 model2 相关字段的存在/不存在(Null/Not-Null)和属性值(如果 model2相关领域存在)。这会很方便,我认为不太具体。

最后,是的,当我不为我的model1__model2__property 请求此自定义过滤器时,一切正常 :-)

【问题讨论】:

    标签: django django-admin django-filter


    【解决方案1】:

    这似乎是 Django 中的一个错误,当您的过滤器路径(元组的第一个元素)有双下划线时...在您的情况下是 'model1__model2__property'

    注意:现在已在 Django 1.7 中修复

    更多细节在这里: https://code.djangoproject.com/ticket/19182

    它非常难看,但到目前为止,我发现的唯一解决方法是将这个固定和覆盖的方法粘贴到您要使用该 list_filterModelAdmin 中:

    def lookup_allowed(self, lookup, value):
        """
        Copy and pasted from ModelAdmin to fix bug in Django
        https://code.djangoproject.com/ticket/19182
        """
        from django.db.models.constants import LOOKUP_SEP
        from django.db.models.sql.constants import QUERY_TERMS
        from django.contrib.admin import FieldListFilter
        from django.contrib.admin import widgets
    
        model = self.model
        # Check FKey lookups that are allowed, so that popups produced by
        # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to,
        # are allowed to work.
        for l in model._meta.related_fkey_lookups:
            for k, v in widgets.url_params_from_lookup_dict(l).items():
                if k == lookup and v == value:
                    return True
    
        parts = lookup.split(LOOKUP_SEP)
    
        # Last term in lookup is a query term (__exact, __startswith etc)
        # This term can be ignored.
        if len(parts) > 1 and parts[-1] in QUERY_TERMS:
            parts.pop()
    
        # Special case -- foo__id__exact and foo__id queries are implied
        # if foo has been specificially included in the lookup list; so
        # drop __id if it is the last part. However, first we need to find
        # the pk attribute name.
        rel_name = None
        for part in parts[:-1]:
            try:
                field, _, _, _ = model._meta.get_field_by_name(part)
            except FieldDoesNotExist:
                # Lookups on non-existants fields are ok, since they're ignored
                # later.
                return True
            if hasattr(field, 'rel'):
                model = field.rel.to
                rel_name = field.rel.get_related_field().name
            elif isinstance(field, RelatedObject):
                model = field.model
                rel_name = model._meta.pk.name
            else:
                rel_name = None
        if rel_name and len(parts) > 1 and parts[-1] == rel_name:
            parts.pop()
    
        if len(parts) == 1:
            return True
        clean_lookup = LOOKUP_SEP.join(parts)
        // FIX BEGINS:
        valid_lookups = [self.date_hierarchy]
        for filter_item in self.list_filter:
            if callable(filter_item):
                valid_lookups.append(filter_item.parameter_name)
            elif isinstance(filter_item, (list, tuple)):
                valid_lookups.append(filter_item[0])
            else:
                valid_lookups.append(filter_item)
        return clean_lookup in valid_lookups
    

    【讨论】:

      猜你喜欢
      • 2018-01-15
      • 1970-01-01
      • 2018-06-25
      • 2018-03-15
      • 2011-09-03
      • 2012-08-19
      • 2010-11-02
      • 2018-10-19
      相关资源
      最近更新 更多