Ich benutze Django 1.0.2. Ich habe eine ModelForm geschrieben, die von einem Model unterstützt wird. Dieses Modell hat einen ForeignKey, wobei blank = False ist. Wenn Django HTML für dieses Formular generiert, wird ein Auswahlfeld mit einer Option für jede Zeile in der Tabelle erstellt, auf die der ForeignKey verweist. Außerdem wird oben in der Liste eine Option erstellt, die keinen Wert hat und als eine Reihe von Strichen angezeigt wird:
<option value="">---------</option>
Was ich gerne wissen würde ist:
- Was ist der sauberste Weg, um diese automatisch generierte Option aus dem Auswahlfeld zu entfernen?
Was ist der sauberste Weg, um es so anzupassen, dass es wie folgt angezeigt wird:
<option value="">Select Item</option>
Auf der Suche nach einer Lösung stieß ich auf das Django-Ticket 4653, das den Eindruck erweckte, dass andere die gleiche Frage hatten und dass das Standardverhalten von Django möglicherweise geändert wurde. Dieses Ticket ist über ein Jahr alt und ich hatte gehofft, dass es einen saubereren Weg gibt, um diese Dinge zu erreichen.
Vielen Dank für jede Hilfe,
Jeff
Bearbeiten: Ich habe das ForeignKey-Feld als solches konfiguriert:
verb = models.ForeignKey(Verb, blank=False, default=get_default_verb)
Dies setzt die Standardeinstellung so, dass es nicht mehr die Option "Leer / Bindestriche" ist, aber leider scheint es keine meiner Fragen zu lösen. Das heißt, die Option leer / Bindestriche wird weiterhin in der Liste angezeigt.
Antworten:
Ich habe das noch nicht getestet, aber basierend auf dem Lesen von Djangos Code hier und hier glaube ich, dass es funktionieren sollte:
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
BEARBEITEN : Dies ist dokumentiert , obwohl Sie nicht unbedingt nach ModelChoiceField suchen müssen, wenn Sie mit einem automatisch generierten ModelForm arbeiten.
EDIT : Wie jlpp Notizen in seiner Antwort nicht abgeschlossen ist - Sie müssen neu ordnen die Auswahl der Widgets nach dem empty_label Attribut ändern. Da dies etwas hackig ist, überschreibt die andere Option, die möglicherweise leichter zu verstehen ist, nur das gesamte ModelChoiceField:
class ThingForm(models.ModelForm): verb = ModelChoiceField(Verb.objects.all(), empty_label=None) class Meta: model = Thing
quelle
aus den Dokumenten
Stellen Sie also die Standardeinstellung ein und Sie sind in Ordnung
quelle
Mit Carls Antwort als Leitfaden und nachdem ich ein paar Stunden in der Django-Quelle herumgewühlt habe, denke ich, dass dies die vollständige Lösung ist:
So entfernen Sie die leere Option (Erweiterung von Carls Beispiel):
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
Das Anpassen der leeren Optionsbezeichnung ist im Wesentlichen dasselbe:
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
Ich denke, dieser Ansatz gilt für alle Szenarien, in denen ModelChoiceFields als HTML gerendert werden, aber ich bin nicht positiv. Ich habe festgestellt, dass beim Initialisieren dieser Felder ihre Auswahl an das Select-Widget übergeben wird (siehe django.forms.fields.ChoiceField._set_choices). Durch das Festlegen des leeren Labels nach der Initialisierung wird die Auswahlliste des Widgets "Auswählen" nicht aktualisiert. Ich bin mit Django nicht vertraut genug, um zu wissen, ob dies als Fehler angesehen werden sollte.
quelle
Sie können dies für Ihr Modell verwenden:
class MyModel(models.Model): name = CharField('fieldname', max_length=10, default=None)
Standard = Keine ist die Antwort: D.
HINWEIS: Ich habe dies auf Django 1.7 versucht
quelle
blank=False
und mit einem festgelegtendefault
Wert keine leere Auswahloption angezeigt.Für den Django 1.4 müssen Sie lediglich den "Standard" -Wert und "blank = False" im Auswahlfeld festlegen
class MyModel(models.Model): CHOICES = ( (0, 'A'), (1, 'B'), ) choice_field = models.IntegerField(choices=CHOICES, blank=False, default=0)
quelle
Sehen Sie hier für die gesamte Debatte über und Methoden zur Lösung dieses Problems.
quelle
Sie können dies in admin tun:
formfield_overrides = { models.ForeignKey: {'empty_label': None}, }
quelle
self.fields['xxx'].empty_value = None
würde nicht funktionieren Wenn Sie einen FeldtypTypedChoiceField
haben, der keineempty_label
Eigenschaft hat.Was wir tun sollten, ist die erste Wahl zu entfernen:
1. Wenn Sie eine
BaseForm
automatische Erkennung erstellen möchtenTypedChoiceField
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.nur ein paar Formulare können Sie verwenden:
class AddClientForm(forms.ModelForm): def __init__(self, *args, **kwargs): super(AddClientForm, self).__init__(*args, **kwargs) self.fields['xxx'].choices = self.fields['xxx'].choices[1:]
quelle
self.fields['xxx'].choices = self.fields['xxx'].choices[1:]
wenn wir leere Auswahl entfernen möchten. Aber wenn Sie den Titel ersetzen möchten, müssen Sie die erste Wahl als Tupel mit dem ersten leeren Element und dem Titel im zweiten "neu erstellen", z. B.self.fields['xxx'].choices = [('', 'Nothing')] + self.fields['xxx'].choices[1:]
BaseForm
, um alle Formulare anzupassen, also mit for-Schleife.Wenn Sie für ein
ForeignKey
Feld dendefault
Wert für''
das Modell festlegen, wird die leere Option entfernt.verb = models.ForeignKey(Verb, on_delete=models.CASCADE, default='')
Für andere Felder wie
CharField
Sie das einstellen könntendefault
zuNone
, aber dies nicht funktioniert fürForeignKey
Felder in Django 1.11.quelle
Ich habe heute damit rumgespielt und mir gerade eine
feige Hack-Lösung ausgedacht:# 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,)
Jetzt können Sie das
ModelChoiceField
leere Standardetikett nach Belieben anpassen. :-)PS: Keine Abstimmungen erforderlich, nicht schädliche Affenpflaster sind immer griffbereit.
quelle
Für die neueste Version von Django sollte die erste Antwort so sein
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)`
quelle
Ich finde LÖSUNG !!
Aber nicht für ForeignKey :-)
Vielleicht kann ich Dir helfen. Ich habe im Django-Quellcode nachgesehen und festgestellt, dass in django.forms.extras.widgets.SelecteDateWidget () eine Eigenschaft namens none_value ist, die gleich (0, '-----') ist, also habe ich dies in meinem Code getan
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), }
quelle
self.fields[field_name].widget.choices[0] = ('', SOME_FIRST_CHOICE_DISPLAY_VALUE)
Seit Django 1.7 können Sie die Beschriftung für den leeren Wert anpassen, indem Sie Ihrer Auswahlliste in Ihrer Modellfelddefinition einen Wert hinzufügen. Aus der Dokumentation zur Konfiguration der Feldauswahl :
Ich habe die Dokumentation für verschiedene Versionen von Django überprüft und festgestellt, dass dies in Django 1.7 hinzugefügt wurde .
quelle
Hier gibt es viele gute Antworten, aber ich bin immer noch nicht ganz zufrieden mit den Implementierungen. Ich bin auch ein bisschen frustriert darüber, dass ausgewählte Widgets aus verschiedenen Quellen (Fremdschlüssel, Auswahlmöglichkeiten) zu unterschiedlichen Verhaltensweisen führen.
Ich arbeite an einem Design, bei dem ausgewählte Felder immer eine leere Option haben. Wenn sie benötigt werden, wird neben ihnen ein Stern angezeigt, und das Formular wird einfach nicht überprüft, wenn sie leer bleiben. Das heißt, ich kann das empty_label nur für Felder, die nicht
TypedChoiceField
s sind, richtig überschreiben .Hier ist , was das Ergebnis sollte aussehen. Das erste Ergebnis ist immer der Name des Feldes - in meinem Fall das
label
.Folgendes habe ich getan. Das Folgende ist eine überschriebene
__init__
Methode meines Formulars: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]]
quelle
Dies wird komplizierter, wenn die Auswahl Fremdschlüssel sind und wenn Sie die Auswahl anhand einiger Kriterien filtern möchten . In diesem Fall ist
empty_label
das leere Etikett leer, wenn Sie die Auswahl festlegen und dann die Auswahlmöglichkeiten neu zuweisen (Sie können auch hier die Filterung anwenden):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()
Grundsätzlich kann die erste Zeile unter
init
für alle Felder im Formular mit einer Schleife oder Inline-Schleife angewendet werden: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
quelle