2011-07-03 19 views
8

Tôi muốn lọc dữ liệu bằng Django (admin.py) bằng văn bản viết trong hộp văn bản đầu vào HTML. Tôi cần lọc các công ty theo thành phố mà họ đang ở và danh sách tất cả các thành phố quá dài. Tôi muốn thay thế danh sách tất cả các thành phố trong bộ lọc bằng một đầu vào văn bản. Tôi tìm thấy một cái gì đó tương tự đây http://djangosnippets.org/snippets/2429/ nhưng có hai vấn đề:Hộp văn bản đầu vào HTML trong bộ lọc Django admin.py

  1. tác giả không gửi models.py, vì vậy nó được difficuilt để thay đổi mã cho nhu cầu của tôi (+ Chưa có cảm nhận)
  2. có được sử dụng lớp UserFieldFilterSpec (RelatedFilterSpec): nhưng tôi cần phải sử dụng AllValuesFilterSpec thay vì RelatedFilterSpec (nhiều hơn trong tập tin django/contrib/admin/filterspecs.py), bởi vì danh sách các thị trấn trong cùng một lớp như comapny (có shoud bởi lớp của thị xã và họ nên đề cập đến công ty bằng chìa khóa nước ngoài (mối quan hệ ManyToMany), nhưng vì một số lý do nó phải được thực hiện theo cách này)

phần quan trọng của models.py trông giống như sau

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

và một cái gì đó từ admin.py

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

Vì vậy, một lần nữa, tôi cần phải: 1. thay vì danh sách các thành phố od hiển thị một văn bản đầu vào trong bộ lọc Django 2. Sau khi nhập thành phố neme trong văn bản đó, dữ liệu lọc theo thành phố (yêu cầu lọc có thể được gửi bằng một số nút gửi hoặc thông qua javascript)

Cảm ơn hàng năm cho tất cả các bài đăng.

Trả lời

2

Trong khi đó không thực sự là câu hỏi của bạn, điều này nghe có vẻ như một giải pháp hoàn hảo cho Django-Selectables bạn có thể chỉ với một vài dòng thêm Biểu mẫu CharField được AJAX hỗ trợ sẽ có mục nhập được chọn từ danh sách thành phố. Hãy xem các mẫu được liệt kê trong liên kết ở trên.

+0

Đây là thực sự không phải là điều tôi đang tìm kiếm. Vấn đề của tôi là hiển thị bộ lọc nhập văn bản làm việc. Tính năng Tự động điền là tốt đẹp và tôi muốn thêm nó sau này. Dù sao, cảm ơn bạn đã trả lời của bạn. – Jazzuell

+0

ok tôi đã tự mình tìm ra điều này. Tôi đã tạo bộ lọc của riêng mình trong filterspecs.py (Tôi biết rằng đó là cách khó chịu để thực hiện). Nếu bạn thử nó theo cách này là cẩn thận về việc đăng ký bộ lọc của bạn. Bộ lọc của bạn phải được đăng ký trước bộ lọc hệ thống. Hơn trong models.py gán bộ lọc của bạn để phân phối nó thuộc về. Trong bộ lọc tôi đã sử dụng thứ gì đó thay đổi được đăng url ở đâu là các tham số. Lọc bởi một thành phố được thực hiện bởi thành phố = Prague nhưng nếu bạn muốn lọc theo danh sách các bộ lọc bạn sử dụng city__in = Prague, Wien, Dublin. Có rất nhiều cách đẹp hơn để làm điều này (truy vấn, AJAX, ..) nhưng tôi chỉ đang học. – Jazzuell

12

Trong trường hợp bất kỳ ai vẫn cần điều này. Nó là ít hackish trong mẫu, nhưng thực hiện mà không có một phần của 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 %} 

Sau đó, theo mô hình của bạn

Sẵn sàng để sử dụng bộ lọc sẽ trông như thế này.

+1

Cảm ơn bạn rất nhiều vì đoạn mã này! Bạn chỉ cần tiết kiệm cho tôi một số giờ làm việc. Tuy nhiên, có một lỗi nhỏ trong ví dụ của bạn: Lệnh gọi 'CatalogCityFilter.queryset' sẽ trả về bộ truy vấn. – devsnd

+0

@devsnd Mã này có tăng ngoại lệ trong trường hợp của bạn không? Như tôi đã nhìn thấy từ các nguồn django: cho filter_spec trong self.filter_specs: new_qs = filter_spec.queryset (yêu cầu, qs) nếu new_qs không phải là None: qs = new_qs https://github.com/django/django/ blob/master/django/contrib/admin/views/main.py # L325 nếu bộ lọc trả về Không có gì xảy ra. –

+0

Không ngoại lệ, nhưng nó không hoạt động trước khi trả về bộ truy vấn, vì 'bộ lọc' trả về một bản sao mới của bộ truy vấn với bộ lọc được áp dụng. – devsnd

0

Tôi đang chạy Django 1.10, 1.11 và r_black 's solution không hoàn toàn phù hợp vì Django đã phàn nàn rằng các lĩnh vực lọc phải kế thừa từ 'FieldListFilter'.

Vì vậy, một thay đổi đơn giản cho bộ lọc để kế thừa từ FieldListFilter đã chăm sóc Django phàn nàn và không phải chỉ định một lớp mới cho từng trường, cả hai cùng một lúc.

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 
     },) 

mẫu/admin/textinput_filter.html (không thay đổi):

{% 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 %} 

Cách sử dụng:

class MyAdmin(admin.ModelAdmin): 
    list_display = [your fields] 
    list_filter = [('field 1', SingleTextInputFilter), ('field 2', SingleTextInputFilter), further fields] 
Các vấn đề liên quan