Django admin.py过滤器中的HTML输入文本框

时间:2011-07-03 13:37:04

标签: html django input filter admin

我想在Django(admin.py)中过滤数据,并在HTML输入文本框中写入文本。我需要按城市过滤公司,所有城市的列表都太长。我想用一个文本输入替换过滤器中所有城市的列表。我找到了类似的东西 这里http://djangosnippets.org/snippets/2429/但有两个问题:

  1. 作者没有发布models.py,所以根据我的需要更改代码是困难的(+没有评论)
  2. 使用了类UserFieldFilterSpec(RelatedFilterSpec):但我需要使用AllValuesFilterSpec而不是RelatedFilterSpec(更多在文件django / contrib / admin / filterspecs.py中),因为城镇列表与comapny属于同一类(有shoud)按城镇类别,他们应该通过外键(ManyToMany关系)引用公司,但由于某些原因,必须以这种方式完成)
  3. 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.在该文本输入中输入城市neme后,按城市过滤数据(过滤请求可以通过一些提交按钮或通过javascript发送)

    感谢yoy所有帖子。

4 个答案:

答案 0 :(得分:14)

如果有人仍然需要这个。它在模板中有点小,但在没有js的情况下实现。

filters.py

from django.contrib.admin import ListFilter
from django.core.exceptions import ImproperlyConfigured


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

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

然后根据admin.py中的模型:

class CatalogCityFilter(SingleTextInputFilter):
    title = 'City'
    parameter_name = 'city'

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

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

准备使用过滤器看起来像这样。

答案 1 :(得分:2)

虽然这实际上不是你的问题,但这听起来像是Django-Selectables的完美解决方案,只需几行就可以添加一个AJAX驱动的CharField表单,它将从城市列表中选择条目。请查看上面链接中列出的示例。

答案 2 :(得分:2)

我正在运行Django 1.10,1.11并且r_blacksolution并不完全适合,因为Django抱怨过滤字段必须继承自'FieldListFilter'。

因此,过滤器从FieldListFilter继承的简单更改可以解决Django抱怨而不必同时为每个字段指定新类。

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

templates / admin / textinput_filter.html(未更改):

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

用法:

bool read_file(int row, int column, char *file_name, float **elems)
    {
    int i, j;
    FILE *pfile;

    fopen_s(&pfile, file_name, "r");
    if (pfile == NULL) {
        return false;
    }

    fscanf_s(pfile, "%d", &row);
    fscanf_s(pfile, "%d", &column);
    //printf_s("%d %d\n", row,column);

    for (i = 0; i < row; i++)
    {
        for (j = 0; j < column; j++) {
            fscanf_s(pfile, "%f", &elems[i][j]);
            //printf("%f\n", elems[i][j]);
        }
    }return true;
 }

答案 3 :(得分:0)

下面是查询集函数中字段名称的修正。

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):

    variable_column = self.parameter_name
    search_type = 'icontains'
    filter = variable_column + '__' + search_type

    if self.value():
        return queryset.filter(**{filter: 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
    }, )