自定义 Django CheckboxSelectMultiple 小部件呈现为空列表
我正在尝试创建一个 CheckboxSelectMultiple 小部件,其中列出了我的项目的所有内容类型。我首先在 ModelForm 中定义 MultipleChoiceField 字段时使用基本小部件,并且效果很好。我现在想将其设为一个自定义小部件,我可以通过应用程序将其导入到任何项目中。
这是我正在使用的代码:
# myapp/models.py
from django.db import models
class Tiger(models.Model):
color = models.CharField(max_length=100)
# myapp/admin.py
from django import forms
from django.contrib import admin
from django.contrib.contenttypes.models import ContentType
from myapp.models import Tiger
class TigerForm(forms.ModelForm):
"""
Default ModelForm that will be overriden.
"""
class Meta:
model = Tiger
这是我定义自定义小部件的地方。我猜我没有正确传递值列表(请参阅代码中的注释)。
class TigerWidget(forms.CheckboxSelectMultiple):
"""
Custom widget that displays a list of checkboxes for each content type.
The goal is to make it generic enough to put it in an external app
that can be imported into any project.
"""
def __init__(self, attrs=None, choices=()):
# List all content types
content_types = ContentType.objects.all()
classes = tuple([(c.model, c.name) for c in content_types])
# Define widget choices as the list of these content types
self.choices = classes # I am guessing it should be done differently?
# Select all of them by default
self.initial = [c[0] for c in classes]
# Same behavior as parent
super(TigerWidget, self).__init__(attrs)
以下是使用它的其余类。
class TigerCustomForm(TigerForm):
"""
Custom form that adds a field using the custom widget to the form.
"""
# content_types = ContentType.objects.all()
# classes = tuple([(c.model, c.name) for c in content_types])
# This works fine.
# nickname = forms.MultipleChoiceField(
# widget=forms.CheckboxSelectMultiple,
# choices=classes,
# # Select all by default
# initial=[c[0] for c in classes]
# )
# This does not. An empty list (<ul></ul>) is rendered in the place of the widget.
nickname = forms.MultipleChoiceField(
widget=TigerWidget,
)
class TigerAdmin(admin.ModelAdmin):
form = TigerCustomForm
admin.site.register(Tiger, TigerAdmin)
admin.site.register(ContentType)
预先感谢您的帮助。
I am trying to create a CheckboxSelectMultiple widget that lists all the content types of my project. I started by using the base widget when defining a MultipleChoiceField field in a ModelForm and it worked fine. I would like now to make it a custom widget I can import though an app into any project.
Here is the code I am using:
# myapp/models.py
from django.db import models
class Tiger(models.Model):
color = models.CharField(max_length=100)
# myapp/admin.py
from django import forms
from django.contrib import admin
from django.contrib.contenttypes.models import ContentType
from myapp.models import Tiger
class TigerForm(forms.ModelForm):
"""
Default ModelForm that will be overriden.
"""
class Meta:
model = Tiger
This is where I define my custom widget. I am guessing I am not passing the list of values correctly (see comment in the code).
class TigerWidget(forms.CheckboxSelectMultiple):
"""
Custom widget that displays a list of checkboxes for each content type.
The goal is to make it generic enough to put it in an external app
that can be imported into any project.
"""
def __init__(self, attrs=None, choices=()):
# List all content types
content_types = ContentType.objects.all()
classes = tuple([(c.model, c.name) for c in content_types])
# Define widget choices as the list of these content types
self.choices = classes # I am guessing it should be done differently?
# Select all of them by default
self.initial = [c[0] for c in classes]
# Same behavior as parent
super(TigerWidget, self).__init__(attrs)
Here are the remaining classes that make use of it.
class TigerCustomForm(TigerForm):
"""
Custom form that adds a field using the custom widget to the form.
"""
# content_types = ContentType.objects.all()
# classes = tuple([(c.model, c.name) for c in content_types])
# This works fine.
# nickname = forms.MultipleChoiceField(
# widget=forms.CheckboxSelectMultiple,
# choices=classes,
# # Select all by default
# initial=[c[0] for c in classes]
# )
# This does not. An empty list (<ul></ul>) is rendered in the place of the widget.
nickname = forms.MultipleChoiceField(
widget=TigerWidget,
)
class TigerAdmin(admin.ModelAdmin):
form = TigerCustomForm
admin.site.register(Tiger, TigerAdmin)
admin.site.register(ContentType)
Thanks in advance for your help.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
小部件负责渲染 html,例如显示多个选择框 (
forms.MultipleSelect
) 或多个复选框 (forms.CheckboxSelectMultiple
)。这是与字段显示选项不同的决定。我认为最好将
forms.MultipleChoiceField
子类化并在那里设置选择。A widget is responsible for rendering the html e.g. display a multiple select box (
forms.MultipleSelect
) or multiple checkboxes (forms.CheckboxSelectMultiple
). This is a separate decision from the choices to display for the field.I think it would be better to subclass
forms.MultipleChoiceField
and set the choices there.我设法通过自定义字段将选择传递给自定义小部件来找到解决方法。初始参数继承自 Field 类,我在自定义 Field 构造函数方法中定义了它。
这是最终的代码:
I managed to find a workaround by passing the choices to the custom widget through the custom field. The initial parameter being inherited from the Field class, I defined it in the custom Field constructor method.
Here the final code: