使用 select 标签渲染 django_tables2.Column(已更新)
Render django_tables2.Column with select tag inside (UPDATED)
我已经编写了一个自定义 editable table,其中包含来自 django_tables2.Column
的子 class 列,但一直在努力渲染 select 标签在我的自定义专栏中。考虑模型:
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
稍后在我的 table class 中这样调用:
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>
文本而不是 select 字段。在这种情况下我做错了什么?我正在使用 Python 2.7、Django 1.8 和 django-tables2 1.16.0。预先感谢您的建议!
更新
我像这样更改了我的自定义列 class:
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
列使用了库 class,而 options
列使用了从它继承的自定义 class 吗?如果是这样,我的 subclass 缺少什么?
另一个更新
我弄清楚了之前选择的问题是什么,虽然它没有解决问题:(问题是我传递了模型实例的字段used_as
,它被设置为None
,因此它永远不会填充 ChoiceField。因此,我将自定义列 class 回滚到初始变体,并在 table class 而不是
used_as = ChoicesColumn(
choices=lambda record: record.used_as.choices()
)
我导入了 MyModelChoices
枚举并使用它代替了模型实例
used_as = ChoicesColumn(choices=MyModelChoices.choices())
现在我看到传递给构造函数的选项,尽管由于某些神秘原因仍未调用 render
方法 =/
现在的最后更新
至于目前我的自定义列和 table 看起来像这样:
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')
ChoiceColumn
渲染方法和 table class 中的相应方法从未在渲染阶段调用(与其他列不同),我完全放弃了。求求你,要么开枪打死我,要么告诉我我到底哪里是个白痴:)
所以,正如我无意中发现的那样,问题出在 accessor
属性中 – 当从
更改时
used_as = ChoiceColumn(UsedAs.choices(), accessor='used_as')
至
used_as = ChoiceColumn(UsedAs.choices(), accessor='pk')
终于渲染出来了。我不明白为什么会这样,如果有人向我解释一下,我将不胜感激。
有一个更简单的方法:
如果您有枚举列(比如 used_as
),您可以更改渲染器以显示 value
(而不是 name
)。将其放在 Table 定义中(在 class MyTable(tables.Table)
中)。
def render_used_as(self,value):
v = value.split(".")[1]
members = MyModelChoices.__members__
return (members[v].value)
请注意,我对枚举使用了一些不同的语法
from enum import Enum
Class MyModelChoices(Enum):
First = 'First'
Second = 'Second'
Third = 'Third'
注意:render_used_as
是 render_%s
,其中 %s = 变量名
我已经编写了一个自定义 editable table,其中包含来自 django_tables2.Column
的子 class 列,但一直在努力渲染 select 标签在我的自定义专栏中。考虑模型:
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
稍后在我的 table class 中这样调用:
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>
文本而不是 select 字段。在这种情况下我做错了什么?我正在使用 Python 2.7、Django 1.8 和 django-tables2 1.16.0。预先感谢您的建议!
更新
我像这样更改了我的自定义列 class:
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
列使用了库 class,而 options
列使用了从它继承的自定义 class 吗?如果是这样,我的 subclass 缺少什么?
另一个更新
我弄清楚了之前选择的问题是什么,虽然它没有解决问题:(问题是我传递了模型实例的字段used_as
,它被设置为None
,因此它永远不会填充 ChoiceField。因此,我将自定义列 class 回滚到初始变体,并在 table class 而不是
used_as = ChoicesColumn(
choices=lambda record: record.used_as.choices()
)
我导入了 MyModelChoices
枚举并使用它代替了模型实例
used_as = ChoicesColumn(choices=MyModelChoices.choices())
现在我看到传递给构造函数的选项,尽管由于某些神秘原因仍未调用 render
方法 =/
现在的最后更新 至于目前我的自定义列和 table 看起来像这样:
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')
ChoiceColumn
渲染方法和 table class 中的相应方法从未在渲染阶段调用(与其他列不同),我完全放弃了。求求你,要么开枪打死我,要么告诉我我到底哪里是个白痴:)
所以,正如我无意中发现的那样,问题出在 accessor
属性中 – 当从
used_as = ChoiceColumn(UsedAs.choices(), accessor='used_as')
至
used_as = ChoiceColumn(UsedAs.choices(), accessor='pk')
终于渲染出来了。我不明白为什么会这样,如果有人向我解释一下,我将不胜感激。
有一个更简单的方法:
如果您有枚举列(比如 used_as
),您可以更改渲染器以显示 value
(而不是 name
)。将其放在 Table 定义中(在 class MyTable(tables.Table)
中)。
def render_used_as(self,value):
v = value.split(".")[1]
members = MyModelChoices.__members__
return (members[v].value)
请注意,我对枚举使用了一些不同的语法
from enum import Enum
Class MyModelChoices(Enum):
First = 'First'
Second = 'Second'
Third = 'Third'
注意:render_used_as
是 render_%s
,其中 %s = 变量名