私はDjango 1.0.2を使用しています。モデルに裏打ちされたModelFormを作成しました。このモデルには、blank = FalseのForeignKeyがあります。WhenDjangoこのフォームのHTMLを生成し、ForeignKeyによって参照されるテーブルの各行に1つのオプションを持つ選択ボックスを作成し、リストの上部に値を持たない一連のダッシュとして表示するオプションも作成します。
<option value="">---------</option>
私が知りたいのは:
それをカスタマイズする最もクリーンな方法は何ですか:
<option value="">Select Item</option>
ソリューションを探していると、私は Djangoチケット465 に出会いました。これは、他の人にも同じ質問があり、Djangoのデフォルトの動作が変更された可能性があります。このチケットは1年以上前のものなので、これらのことを達成するためのよりクリーンな方法があるかもしれないと期待していました。
助けてくれてありがとう、
ジェフ
編集:ForeignKeyフィールドを次のように構成しました:
verb = models.ForeignKey(Verb, blank=False, default=get_default_verb)
これによりデフォルトが設定され、空/ダッシュオプションではなくなりますが、残念ながら私の質問のいずれも解決しないようです。つまり、空/ダッシュオプションはリストに表示されたままです。
これはテストしていませんが、Djangoのコードの読み取りに基づいています here および here
class ThingForm(models.ModelForm):
class Meta:
model = Thing
def __init__(self, *args, **kwargs):
super(ThingForm, self).__init__(*args, **kwargs)
self.fields['verb'].empty_label = None
[〜#〜] edit [〜#〜]:これは 文書化された ですが、必ずしも見る必要があるとは限りません自動生成されたModelFormを使用している場合は、ModelChoiceFieldの場合。
[〜#〜] edit [〜#〜]:jlppが彼の答えで述べているように、これは完全ではありません。 empty_label属性を変更した後のウィジェットの選択。それは少しハックなので、理解しやすいかもしれない他のオプションは、ModelChoiceField全体をオーバーライドすることです。
class ThingForm(models.ModelForm):
verb = ModelChoiceField(Verb.objects.all(), empty_label=None)
class Meta:
model = Thing
ドキュメントから
モデルフィールドにblank = Falseと明示的なデフォルト値がある場合、空白の選択肢は含まれません(代わりにデフォルト値が最初に選択されます)。
デフォルトを設定すれば大丈夫です
Carlの答えをガイドとして、Djangoソースを数時間根ざした後、これは完全なソリューションだと思います。
空のオプションを削除するには(Carlの例を拡張):
class ThingForm(models.ModelForm):
class Meta:
model = Thing
def __init__(self, *args, **kwargs):
super(ThingForm, self).__init__(*args, **kwargs)
self.fields['verb'].empty_label = None
# following line needed to refresh widget copy of choice list
self.fields['verb'].widget.choices =
self.fields['verb'].choices
空のオプションラベルをカスタマイズするには、基本的に同じです。
class ThingForm(models.ModelForm):
class Meta:
model = Thing
def __init__(self, *args, **kwargs):
super(ThingForm, self).__init__(*args, **kwargs)
self.fields['verb'].empty_label = "Select a Verb"
# following line needed to refresh widget copy of choice list
self.fields['verb'].widget.choices =
self.fields['verb'].choices
このアプローチは、ModelChoiceFieldsがHTMLとしてレンダリングされるすべてのシナリオに適用されると思いますが、私は肯定的ではありません。これらのフィールドが初期化されると、選択がSelectウィジェットに渡されることがわかりました(Django.forms.fields.ChoiceField._set_choicesを参照)。初期化後にempty_labelを設定しても、選択ウィジェットの選択リストは更新されません。 Djangoに十分に精通していないため、これをバグと見なすべきかどうかを知ることができます。
モデルでこれを使用できます:
class MyModel(models.Model):
name = CharField('fieldname', max_length=10, default=None)
デフォルト=なしは答えです:D
注:Django 1.7でこれを試しました
Django 1.4に関しては、選択肢フィールドに「デフォルト」値と「blank = False」を設定するだけです。
class MyModel(models.Model):
CHOICES = (
(0, 'A'),
(1, 'B'),
)
choice_field = models.IntegerField(choices=CHOICES, blank=False, default=0)
あなたは管理者でこれを行うことができます:
formfield_overrides = {
models.ForeignKey: {'empty_label': None},
}
この問題の完全な議論と解決方法については、 こちら をご覧ください。
self.fields['xxx'].empty_value = None
は、フィールドタイプがTypedChoiceField
で、empty_label
プロパティ。
私たちがすべきことは、最初の選択肢を削除することです:
1 BaseForm
自動検出TypedChoiceField
を構築する場合
class BaseForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(BaseForm, self).__init__(*args, **kwargs)
for field_name in self.fields:
field = self.fields.get(field_name)
if field and isinstance(field , forms.TypedChoiceField):
field.choices = field.choices[1:]
# code to process other Field
# ....
class AddClientForm(BaseForm):
pass
2.ごく少数のフォーム、使用できます:
class AddClientForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(AddClientForm, self).__init__(*args, **kwargs)
self.fields['xxx'].choices = self.fields['xxx'].choices[1:]
ForeignKey
フィールドの場合、モデルでdefault
値を''
に設定すると、空白のオプションが削除されます。
verb = models.ForeignKey(Verb, on_delete=models.CASCADE, default='')
CharField
などの他のフィールドでは、default
をNone
に設定できますが、Django 1.11のForeignKey
フィールドでは機能しません。
私は今日これをいじくり回していて、ちょうど思いついた ward病なハック 気の利いたソリューション:
# Cowardly handle ModelChoiceField empty label
# we all hate that '-----' thing
class ModelChoiceField_init_hack(object):
@property
def empty_label(self):
return self._empty_label
@empty_label.setter
def empty_label(self, value):
self._empty_label = value
if value and value.startswith('-'):
self._empty_label = 'Select an option'
ModelChoiceField.__bases__ += (ModelChoiceField_init_hack,)
これで、デフォルトのModelChoiceField
空のラベルを好きなものに微調整できます。 :-)
PS:ダウンボートの必要はありません。無害なサルのパッチは常に便利です。
Django=の最新バージョンの場合、最初の答えは次のようになります
class ThingForm(models.ModelForm):
class Meta:
model = Thing
def __init__(self, *args, **kwargs):
self.base_fields['cargo'].empty_label = None
super(ThingForm, self).__init__(*args, **kwargs)`
私は解決策を見つけます!!
ただし、ForeignKeyではありません:-)
たぶん私はあなたを助けることができます。 Djangoソースコードを見て、Django.forms.extras.widgets.SelecteDateWidget()でnone_valueというプロパティが(0、 '-----')と等しいことを発見したので、私のコードでこれをしました
class StudentForm(ModelForm):
class Meta:
this_year = int(datetime.datetime.today().strftime('%Y'))
birth_years = []
years = []
for year in range(this_year - 2, this_year + 3 ):
years.append(year)
for year in range(this_year - 60, this_year+2):
birth_years.append(year)
model = Student
exclude = ['user', 'fullname']
date_widget = SelectDateWidget(years=years)
date_widget.__setattr__('none_value', (0, 'THERE WAS THAT "-----" NO THERES THIS:-)'))
widgets = {
'beginning': date_widget,
'birth': SelectDateWidget(years=birth_years),
}
選択肢が外部キーで、何らかの基準に基づいて選択肢をフィルタリングするの場合、これはより複雑になります。このような場合、empty_label
を設定してから選択肢を再割り当てすると(ここでもフィルターを適用できます)、空のラベルは空白になります。
class ThingForm(models.ModelForm):
class Meta:
model = Thing
def __init__(self, *args, **kwargs):
super(ThingForm, self).__init__(*args, **kwargs)
self.fields['verb'].empty_label = None
self.fields['verb'].queryset=Verb.objects.all()
基本的に、init
の下の最初の行は、ループまたはインラインループのあるフォームのすべてのフィールドに適用できます。
def __init__(self,user, *args, **kwargs):
super(NewTicket, self).__init__(*args, **kwargs)
for f in self.fields:
self.fields[f].empty_label = None # or "Please Select" etc
ここにはたくさんの素晴らしい答えがありますが、私はまだ実装に完全には満足していません。また、さまざまなソース(外部キー、選択肢)からウィジェットを選択すると、さまざまな動作が得られることにも少しイライラしています。
私は、選択フィールドalwaysに空白のオプションがあり、必要な場合は横に星が付いているデザインを使用していますまた、フォームが空のままの場合、フォームは検証されません。そうは言っても、TypedChoiceField
sではないフィールドのempty_labelのみを適切にオーバーライドできます。
結果shouldは次のようになります。最初の結果は常にフィールドの名前です-私の場合、label
です。
これが私がやったことです。以下は、オーバーライドされた__init__
私のフォームのメソッド:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for _, field in self.fields.items():
if hasattr(field, 'empty_label'):
field.empty_label = field.label
if isinstance(field, forms.TypedChoiceField):
field.choices = [('', field.label)] + [choice for choice in field.choices if choice[0]]
Django 1.7であるため、モデルフィールド定義の選択リストに値を追加することにより、空白値のラベルをカスタマイズできます。設定に関するドキュメントから フィールドの選択肢 :
デフォルトで空白= Falseがフィールドに設定されていない場合、「---------」を含むラベルが選択ボックスでレンダリングされます。この動作をオーバーライドするには、Noneを含む選択肢にTupleを追加します。例えば(なし、「表示する文字列」)。または、CharFieldのように、これが理にかなっている場合はNoneの代わりに空の文字列を使用できます。
Django=の異なるバージョンのドキュメントを確認し、これが added Django 1.7 。