【问题标题】:Render django_tables2.Column with select tag inside (UPDATED)渲染 django_tables2.Column 与内部选择标签(更新)
【发布时间】:2019-02-14 23:43:25
【问题描述】:

我已经编写了一个自定义的可编辑表格,其中的列是django_tables2.Column 的子类,但在我的自定义列中呈现选择标记时一直在苦苦挣扎。考虑模型:

myapp/models.py

from django.db import models
from myapp.utils.enums import MyModelChoices


class MyModel(models.Model):
    bound_model = models.ForeignKey(
        SomeOtherModel,
        related_name='bound_model'
    )

    used_as = models.CharField(
        max_length=50,
        blank=True,
        null=True,
        choices=MyModelChoices.choices()
    )

和我在 myapp/utils/enums.py 中的枚举:

class MyModelChoices:
    __metaclass__ = EnumMeta  # Logic irrelevant

    First = 'First',
    Second = 'Second',
    Third = 'Third'

我最终得到这样的自定义列:

import django_tables2 as tables
from django.forms import ChoiceField

class ChoicesColumn(tables.Column):
    def __init__(self, choices, attrs=None, **extra):
        self.choices = choices
        kwargs = {'orderable': False, 'attrs': attrs}
        kwargs.update(extra)
        super(ChoicesColumn, self).__init__(**kwargs)

    def render(self, value, bound_column):
        select = ChoiceField(choices=self.choices)
        return select.widget.render(
            bound_column.name,
            self.label_to_value(value)
        )

    def label_to_value(self, label):
        for (v, l) in self.choices:
            if l == label:
                return v

稍后在我的表类中这样调用:

import django_tables2 as tables
from myapp.models import MyModel
from myapp.tables.utils import ChoicesColumn

class MyTable(tables.Table):
    name = tables.Column()
    used_as = ChoicesColumn(
        choices=lambda record: record.used_as.choices()
    )

    def render_name(self, record):
        return record.bound_model.name

    class Meta:
        model = MyModel
        fields = ('name', 'used_as',)

但仍然只呈现了一个普通的<td></td>,带有文本而不是选择字段。在这种情况下我做错了什么?我正在使用 Python 2.7、Django 1.8 和 django-tables2 1.16.0。提前感谢您的建议!

更新

我像这样更改了我的自定义列类:

class ChoicesColumn(tables.Column):
    def __init__(self, attrs=None, **extra):
        kwargs = {'orderable': False, 'attrs': attrs}
        kwargs.update(extra)
        super(ChoicesColumn, self).__init__(**kwargs)

    def render(self, value, bound_column):
        options = [self.render_option(c) for c in value]
        html_template = '''
                        <select name={}>{}</select>
                        '''.format(bound_column.name, options)
        return mark_safe(html_template)

    def render_option(self, choice):
        return '<option value={0}>{0}</option>'.format(choice)

并根据文档中的this paragraph 添加了render_options 方法:

class MyTable(tables.Table):
    name = tables.Column(accessor='pk')
    # With or without accessor it doesn't work neither way
    used_as = ChoicesColumn(accessor='used_as')

    def render_name(self, record):
        return record.bound_model.name

    def render_used_as(self, record):
        return record.used_as.choices()

    class Meta:
        model = MyModel,
        fields = ('name', 'options',)

但是这个方法甚至没有在渲染时执行,这是我在调试时发现的,尽管它之前的方法在我重新加载页面并正确渲染数据时执行。那是因为name 列使用库类,而options 列使用从它继承的自定义类吗?如果是这样,我的子类缺少什么?

另一个更新

我弄清楚了之前的选择问题是什么,虽然它没有解决问题:(问题是我正在传递模型实例的字段used_as,它被设置为None,因此它永远不会填充 ChoiceField。因此,我将自定义列类回滚到初始变体,并在我的表类中而不是

used_as = ChoicesColumn(
    choices=lambda record: record.used_as.choices()
)

我导入了MyModelChoices 枚举并用它代替了模型实例

used_as = ChoicesColumn(choices=MyModelChoices.choices())

现在我看到传递给构造函数的选项,尽管由于某种神秘的原因仍未调用 render 方法 =/

目前的最新更新 至于当前时刻,我的自定义列和表如下所示:

class ChoicesColumn(tables.Column):
    def __init__(self, choices, attrs=None, **extra)
        self.choices = choices
        self.choices.insert(0, ('', '------'))
        kwargs = {'orderable': False, 'attrs': attrs}
        kwargs.update(extra)
        super(ChoicesColumn, self).__init__(**kwargs)

    def render(self, value, bound_column):
        select = forms.ChoiceField(choices=self.choices)
        return select.widget.render(bound_column.name, value)


class MyTable(tables.Table):
    name = tables.Column(accessor='pk')
    used_as = ChoiceColumn(UsedAs.choices(), accessor='used_as')

    def render_name(self, record):
        return record.bound_model.name

    def render_used_as(self, record):
        if record.used_as is None:
            return ''
        return record.used_as

    class Meta:
        model = MyModel
        fields = ('name', 'used_as')

ChoiceColumnrender 方法和 table 类中的相应方法在渲染阶段从不调用(与其他列不同),我完全放弃了。请仁慈地向我开枪或告诉我我到底在哪里是个白痴:)

【问题讨论】:

    标签: python django django-templates django-tables2


    【解决方案1】:

    所以,正如我偶然发现的那样,问题出在accessor 属性中——从

    used_as = ChoiceColumn(UsedAs.choices(), accessor='used_as')
    

    used_as = ChoiceColumn(UsedAs.choices(), accessor='pk')
    

    它终于渲染了。我不明白为什么会这样,如果有人向我解释一下,我将不胜感激。

    【讨论】:

      【解决方案2】:

      有一个更简单的方法:

      如果您有 Enum 列(例如 used_as),您可以更改渲染器以显示 value(而不是 name)。将其放在表定义中(在 class MyTable(tables.Table) 中)。

      def render_used_as(self,value):
          v = value.split(".")[1]
          members = MyModelChoices.__members__
          return (members[v].value)
      

      请注意,我对 Enum 使用了一些不同的语法

      from enum import Enum
      Class MyModelChoices(Enum):
         First = 'First'
         Second = 'Second'
         Third = 'Third'
      

      注意:render_used_asrender_%s,%s = 变量名

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-12-13
        • 2016-01-28
        • 2011-06-14
        • 2019-11-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多