私はマルチステートのクリックボックスが必要でした。だから私はそれを作る素敵なDjangoのソリューションにいくつかの自由な時間を過ごす:Djangoカスタムウィジェットが上記の選択に失敗しました1(整数を入力してください)
class MultiStateChoiceInput(forms.widgets.ChoiceInput):
input_type = 'radio'
def __init__(self, name, value, attrs, choice, index, label_id):
# Override to use the label_id which is upped with 1
if 'id' in attrs:
self.label_id = attrs['id']+ "_%d" % label_id
super(MultiStateChoiceInput, self).__init__(name, value, attrs, choice, index)
self.value = force_text(self.value)
@property
def id_for_label(self):
return self.label_id
def render(self, name=None, value=None, attrs=None, choices=()):
if self.id_for_label:
label_for = format_html(' for="{}"', self.id_for_label)
else:
label_for = ''
attrs = dict(self.attrs, **attrs) if attrs else self.attrs
return format_html(
'{} <label{}>{}</label>', self.tag(attrs), label_for, self.choice_label
)
class MultiStateRenderer(forms.widgets.ChoiceFieldRenderer):
choice_input_class = MultiStateChoiceInput
outer_html = '<span class="cyclestate">{content}</span>'
inner_html = '{choice_value}{sub_widgets}'
def render(self):
"""
Outputs a <ul> for this set of choice fields.
If an id was given to the field, it is applied to the <ul> (each
item in the list will get an id of `$id_$i`).
# upgraded with the label_id
"""
id_ = self.attrs.get('id')
output = []
for i, choice in enumerate(self.choices):
choice_value, choice_label = choice
if isinstance(choice_label, (tuple, list)):
attrs_plus = self.attrs.copy()
if id_:
attrs_plus['id'] += '_{}'.format(i)
sub_ul_renderer = self.__class__(
name=self.name,
value=self.value,
attrs=attrs_plus,
choices=choice_label,
label_id = (i+1) % (len(self.choices)) # label_id is next one
)
sub_ul_renderer.choice_input_class = self.choice_input_class
output.append(format_html(self.inner_html, choice_value=choice_value,
sub_widgets=sub_ul_renderer.render()))
else:
w = self.choice_input_class(self.name, self.value,
self.attrs.copy(), choice, i, label_id = (i+1) % (len(self.choices))) # label_id is next one
output.append(format_html(self.inner_html,
choice_value=force_text(w), sub_widgets=''))
return format_html(self.outer_html,
id_attr=format_html(' id="{}"', id_) if id_ else '',
content=mark_safe('\n'.join(output)))
class MultiStateSelectWidget(forms.widgets.RendererMixin, forms.widgets.Select):
''' This widget enables multistate clickable toggles
Requires some css as well (see .cyclestate)
'''
renderer = MultiStateRenderer
https://stackoverflow.com/a/33455783/3849359ここで説明すると、クリックがそれに到達するまで、次の状態をトグルし、その後、先頭に続き、そこでれるようにこれは、フォームを作成します。
フォームが似私の見解で呼び出されます。
SomeFormSet= modelformset_factory(myModel, form=myModelForm, extra=0)
SomeFormSet.form = staticmethod(curry(myModelForm, somevariable=somevariable))
formset = SomeFormSet(request.POST or None, queryset=somequeryset)
そしてforms.pyは次のとおりです。
class myModelForm(forms.ModelForm):
CHOICES = (
(0, _('a')),
(1, _('b')),
(2, _('c')),
(3, _('d')),
)
field = forms.IntegerField(widget=MultiStateSelectWidget(choices=CHOICES))
class Meta:
model = MyModal
fields = ('field',)
widgets = {'id': forms.HiddenInput(),
}
def __init__(self, *args, **kwargs):
self.variable= kwargs.pop('variable')
super(myModelForm, self).__init__(*args, **kwargs)
for field in myModelForm.fields:
if self.instance.pk:
if not getattr(self.instance, field):
self.initial[field]= 0
else:
self.initial[field]= 1
if anothercondition:
self.initial[field] = 3
else:
self.initial[field] = 2
私はそれが非常によく働いたと思いました。クリックと保存がうまくいく(私はカスタム保存メソッドがある)。フォームフィールドの値が2または3の場合を除いて、突然エラーメッセージで失敗します。「フィールド」は整数でなければなりません。
私がアイデアを忘れていると誰かが助けてくれると助かりました!
EDIT:ちょっとでも...私はPOSTをチェックして、それは素晴らしいです。唯一の問題は、値が2であればDjangoがPOSTを解析するどこかで値を完全に失うことです(値は2になりますが、理由がわかりません)。
EDIT2:Django ModelFormはモデル検証もしているようです。モデルはBooleanFieldです。これが失敗する理由です。誰かがそれを無効にする良い方法を知っているなら、それはいいでしょう!
整数を保存するには、モデルフィールドをIntegerFieldに変更します。ブール値フィールドに整数を保存することはできません。私はこれが問題だと思います。 – edgarzamora