2011-07-03 137 views
8

我想通過在HTML輸入文本框中寫入文本來過濾Django(admin.py)中的數據。我需要按城市過濾公司,並且所有城市的列表都太長。我想用一個文本輸入來替換過濾器中所有城市的列表。我發現了類似 這裏http://djangosnippets.org/snippets/2429/的東西,但這裏有兩個問題:Django中的HTML輸入文本框admin.py過濾器

  1. 作者沒有公佈models.py,所以它difficuilt改變代碼爲我的需要(+無評論)
  2. 有使用類UserFieldFilterSpec (RelatedFilterSpec):但我需要使用AllValuesFilterSpec而不是RelatedFilterSpec(在文件django/contrib/admin/filterspecs.py中更多),因爲城鎮列表與comapny在同一個類中(城鎮類應該是通過外鍵(ManyToMany關係)引用公司,但由於某些原因必須以此方式完成)

models.py的重要組成部分,看起來像這樣

class Company(models.Model): 
    title = models.CharField(max_length=150,blank=False) 
    city = models.CharField(max_length=50,blank=True) 

,並從東西admin.py

class CatalogAdmin(admin.ModelAdmin): 
    form = CatalogForm 
    list_display = ('title','city') 
    list_filter = ['city',] 

如此反覆,我需要:1。而不是列表 OD城市顯示一個文本在Django過濾器中輸入 2.在該文本輸入中輸入城市名稱後,按城市過濾數據(過濾請求可通過一些提交按鈕或通過javascript發送)

感謝所有職位的同比。

回答

2

雖然它其實不是你的問題,但這聽起來像是Django-Selectables的完美解決方案,只需幾行添加一個AJAX驅動的CharField表單,它將從城市列表中選擇條目。看看上面鏈接中列出的樣本。

+0

這真的不是我所期待的。我的問題是顯示工作文本輸入過濾器。自動填充功能很不錯,我想稍後添加它。無論如何,感謝您的回覆。 – Jazzuell

+0

好吧,我自己想這個。我在filterspecs.py中創建了我自己的過濾器(我知道這是一種討厭的方式)。如果您嘗試使用這種方式,請注意註冊您的過濾器。您的過濾器應在系統過濾器之前註冊。與models.py相比,將過濾器分配給它所屬的屬性。 在過濾器中我使用了一些改變發佈網址的地方,其中的參數。一個城市的過濾由城市=布拉格完成,但如果您想按照過濾器列表進行過濾,請使用city__in = Prague,Wien,Dublin。如何做到這一點有許多更好的方法(查詢,AJAX,..),但我只是在學習。 – Jazzuell

12

如果有人仍然需要這個。它在模板中有點駭人聽聞,但是沒有js的實現。

filters.py

from django.contrib.admin import ListFilter 

class SingleTextInputFilter(ListFilter): 
    """ 
    renders filter form with text input and submit button 
    """ 
    parameter_name = None 
    template = "admin/textinput_filter.html" 

    def __init__(self, request, params, model, model_admin): 
     super(SingleTextInputFilter, self).__init__(
      request, params, model, model_admin) 
     if self.parameter_name is None: 
      raise ImproperlyConfigured(
       "The list filter '%s' does not specify " 
       "a 'parameter_name'." % self.__class__.__name__) 

     if self.parameter_name in params: 
      value = params.pop(self.parameter_name) 
      self.used_parameters[self.parameter_name] = value 

    def value(self): 
     """ 
     Returns the value (in string format) provided in the request's 
     query string for this filter, if any. If the value wasn't provided then 
     returns None. 
     """ 
     return self.used_parameters.get(self.parameter_name, None) 

    def has_output(self): 
     return True 

    def expected_parameters(self): 
     """ 
     Returns the list of parameter names that are expected from the 
     request's query string and that will be used by this filter. 
     """ 
     return [self.parameter_name] 


    def choices(self, cl): 
     all_choice = { 
      'selected': self.value() is None, 
      'query_string': cl.get_query_string({}, [self.parameter_name]), 
      'display': _('All'), 
     } 
     return ({ 
      'get_query': cl.params, 
      'current_value': self.value(), 
      'all_choice': all_choice, 
      'parameter_name': self.parameter_name 
     },) 

textinput_filter.html

{% load i18n %} 
<h3>{% blocktrans with filter_title=title %} By {{ filter_title }} {% endblocktrans %}</h3> 

{#i for item, to be short in names#} 
{% with choices.0 as i %} 
<ul> 
    <li> 
     <form method="get"> 
      <input type="search" name="{{ i.parameter_name }}" value="{{ i.current_value|default_if_none:"" }}"/> 

      {#create hidden inputs to preserve values from other filters and search field#} 
      {% for k, v in i.get_query.items %} 
       {% if not k == i.parameter_name %} 
        <input type="hidden" name="{{ k }}" value="{{ v }}"> 
       {% endif %} 
      {% endfor %} 
      <input type="submit" value="{% trans 'apply' %}"> 
     </form> 
    </li> 

    {#show "All" link to reset current filter#} 
    <li{% if i.all_choice.selected %} class="selected"{% endif %}> 
     <a href="{{ i.all_choice.query_string|iriencode }}"> 
      {{ i.all_choice.display }} 
     </a> 
    </li> 
</ul> 
{% endwith %} 

然後根據你的模型

準備使用過濾器應該是這樣的。

+1

非常感謝您的代碼片段!你剛剛爲我節省了幾個小時的工作。在你的例子中有一個小錯誤:'CatalogCityFilter.queryset'調用應該返回queryset。 – devsnd

+0

@devsnd這段代碼是否在你的情況下引發異常?正如我從django的來源見: 爲FILTER_SPEC在self.filter_specs: new_qs = filter_spec.queryset(請求,QS) 如果new_qs不是無: QS = new_qs https://github.com/django/django/ blob/master/django/contrib/admin/views/main.py#L325 如果過濾器返回None沒有任何反應。 –

+0

沒有例外,但它在返回查詢集之前無效,因爲'filter'返回應用了過濾器的查詢集的新副本。 – devsnd

0

我正在Django的1.10,1.11和FieldListFilter‘r_black「,因爲Django的抱怨該過濾器字段必須繼承小號solution並沒有完全適應’。

因此,從FieldListFilter繼承的過濾器的簡單更改負責Django的抱怨,而不必爲每個字段同時指定新的類。

class SingleTextInputFilter(admin.FieldListFilter): 
    """ 
    renders filter form with text input and submit button 
    """ 

    parameter_name = None 
    template = "admin/textinput_filter.html" 

    def __init__(self, field, request, params, model, model_admin, field_path): 
     super().__init__(field, request, params, model, model_admin, field_path) 
     if self.parameter_name is None: 
      self.parameter_name = self.field.name 

     if self.parameter_name in params: 
      value = params.pop(self.parameter_name) 
      self.used_parameters[self.parameter_name] = value 

    def queryset(self, request, queryset): 
     if self.value(): 
      return queryset.filter(imei__icontains=self.value()) 

    def value(self): 
     """ 
     Returns the value (in string format) provided in the request's 
     query string for this filter, if any. If the value wasn't provided then 
     returns None. 
     """ 
     return self.used_parameters.get(self.parameter_name, None) 

    def has_output(self): 
     return True 

    def expected_parameters(self): 
     """ 
     Returns the list of parameter names that are expected from the 
     request's query string and that will be used by this filter. 
     """ 
     return [self.parameter_name] 

    def choices(self, cl): 
     all_choice = { 
      'selected': self.value() is None, 
      'query_string': cl.get_query_string({}, [self.parameter_name]), 
      'display': _('All'), 
     } 
     return ({ 
      'get_query': cl.params, 
      'current_value': self.value(), 
      'all_choice': all_choice, 
      'parameter_name': self.parameter_name 
     },) 

templates/admin/textinput_filter。HTML(不變):

{% load i18n %} 
<h3>{% blocktrans with filter_title=title %} By {{ filter_title }} {% endblocktrans %}</h3> 

{#i for item, to be short in names#} 
{% with choices.0 as i %} 
<ul> 
    <li> 
     <form method="get"> 
      <input type="search" name="{{ i.parameter_name }}" value="{{ i.current_value|default_if_none:"" }}"/> 

      {#create hidden inputs to preserve values from other filters and search field#} 
      {% for k, v in i.get_query.items %} 
       {% if not k == i.parameter_name %} 
        <input type="hidden" name="{{ k }}" value="{{ v }}"> 
       {% endif %} 
      {% endfor %} 
      <input type="submit" value="{% trans 'apply' %}"> 
     </form> 
    </li> 

    {#show "All" link to reset current filter#} 
    <li{% if i.all_choice.selected %} class="selected"{% endif %}> 
     <a href="{{ i.all_choice.query_string|iriencode }}"> 
      {{ i.all_choice.display }} 
     </a> 
    </li> 
</ul> 
{% endwith %} 

用法:

class MyAdmin(admin.ModelAdmin): 
    list_display = [your fields] 
    list_filter = [('field 1', SingleTextInputFilter), ('field 2', SingleTextInputFilter), further fields]