使用带有django-filter的Textarea for CSVWidget

问题描述 投票:3回答:1

我使用django-filter为大型数据集提供搜索表单。它适用于那些想要提供样本ID并获得过滤列表的科学家。

为了这个目的,我想要<textarea>而不是<input type="text">,因为他们只会一次粘贴十几个或更多的ID,如果他们对提交的值有概述会很好。

这是我的代码:

from django import forms
import django_filters as filters

class TextareaCSVWidget(filters.widgets.BaseCSVWidget, forms.Textarea):
    """
    The widget should create textarea.
    """
    pass

class CharInFilter(filters.BaseInFilter, filters.CharFilter):
    """
    The filter should accept coma separated strings.
    """
    pass

class SampleFilter(filters.FilterSet):
    sample_ids = CharInFilter(
        name='sample_id',
        widget=TextareaCSVWidget()
    )

现在textarea正确显示。搜索按预期工作。

然而,有一个奇怪的问题:当我输入多个值(以逗号分隔)时,在提交搜索表单后,textarea被<input type="text">替换(输入的值被保留)。这看起来很尴尬,我需要防止这种行为。

如果我在textarea中输入单个值,则不会发生这种情况。

我的做法有什么问题?

编辑:

在发布问题之后,我在django-filter的源代码中进行了更好的查看,这里是我用来创建BaseCSVWidget的类TextareaCSVWidget的相关部分:

def render(self, name, value, attrs=None):
    if not self._isiterable(value):
        value = [value]

    if len(value) <= 1:
        # delegate to main widget (Select, etc...) if not multiple values
        value = value[0] if value else ''
        return super(BaseCSVWidget, self).render(name, value, attrs)

    # if we have multiple values, we need to force render as a text input
    # (otherwise, the additional values are lost)
    surrogate = forms.TextInput()
    value = [force_text(format_value(surrogate, v)) for v in value]
    value = ','.join(list(value))

    return surrogate.render(name, value, attrs)

强调的部分是决定性的。我现在应该怎么做?覆盖render方法看起来并不像我。我不想丢失输入的值。

我可以使用JavaScript操作它,并在文档加载时用textarea替换输入元素,如果没有别的帮助。

python django django-filter
1个回答
0
投票

我已经覆盖了render方法,它工作正常。这是我的解决方案:

def render(self, name, value, attrs=None):
    if not self._isiterable(value):
        value = [value]

    if len(value) <= 1:
        # delegate to main widget (Select, etc...) if not multiple values
        value = value[0] if value else ''
        return super(TextareaCSVWidget, self).render(name, value, attrs)

     value = ','.join(value)
     return super(TextareaCSVWidget, self).render(name, value, attrs)

强调的部分是变化。这会正确呈现textarea并保留用户输入。我想作者在创建这个小部件时没有考虑HTML元素textarea,因此强制使用input类型的text元素。例如在<input type="number">中,不可能放置多个彗差分隔值。

如果有人有更好的解决方案,我仍然很乐意得到更好的答案。

© www.soinside.com 2019 - 2024. All rights reserved.