2013-07-01 52 views
1

我想實現的this snippet一個新的版本,使得Django的1.4 1.5自定義過濾器返回SuspiciousOperation

相當多的演變,下面的代碼幾乎工作節選它兼容和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 :-)

回答

2

這似乎是在Django的錯誤請求該自定義過濾器,當你有雙下劃線的滲透路徑(第一工作元組的元素)......在你的情況'model1__model2__property'

注:現在固定在Django 1.7

更多細節在這裏: https://code.djangoproject.com/ticket/19182

這是相當難看,但到目前爲止,我發現的唯一的解決方法是粘貼固定和重寫的方法到您想要使用的ModelAdminlist_filter

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