J'utilise Django 1.0.2. J'ai écrit un ModelForm soutenu par un Model. Ce modèle a une ForeignKey où blank = False. Lorsque Django génère du code HTML pour ce formulaire, il crée une boîte de sélection avec une option pour chaque ligne de la table référencée par la clé étrangère. Il crée également une option en haut de la liste qui n’a aucune valeur et s’affiche sous la forme d’une série de tirets:
<option value="">---------</option>
Ce que j'aimerais savoir, c'est:
Quel est le moyen le plus propre de le personnaliser pour qu’il se présente comme suit:
<option value="">Select Item</option>
En cherchant une solution, je suis tombé sur billet Django 4653 , ce qui m'a donné l'impression que d'autres personnes avaient la même question et que le comportement par défaut de Django avait peut-être été modifié. Ce billet a plus d'un an alors j'espérais qu'il pourrait y avoir un moyen plus propre d'accomplir ces choses.
Merci pour toute aide,
Jeff
Edit: j'ai configuré le champ ForeignKey en tant que tel:
verb = models.ForeignKey(Verb, blank=False, default=get_default_verb)
Ceci définit la valeur par défaut de sorte que ce ne soit plus l'option vide/tirets, mais malheureusement, cela ne semble résoudre aucune de mes questions. C'est-à-dire que l'option vide/tirets apparaît toujours dans la liste.
Je n'ai pas testé cela, mais basé sur la lecture du code de Django ici et ici Je crois que cela devrait fonctionner:
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: Ceci est documenté , bien que vous ne sachiez pas nécessairement que ModelChoiceField est utilisé si vous utilisez un ModelForm généré automatiquement.
EDIT: Comme jlpp le note dans sa réponse, cela n'est pas complet - vous devez réaffecter les choix aux widgets après avoir modifié l'attribut empty_label. Comme c'est un peu compliqué, l'autre option, qui pourrait être plus facile à comprendre, consiste simplement à remplacer tout le ModelChoiceField:
class ThingForm(models.ModelForm):
verb = ModelChoiceField(Verb.objects.all(), empty_label=None)
class Meta:
model = Thing
des docs
Le choix en blanc ne sera pas inclus si le champ du modèle a la valeur vide = False et une valeur par défaut explicite (la valeur par défaut sera initialement sélectionnée ).
alors définissez la valeur par défaut et vous êtes ok
Avec la réponse de Carl comme guide et après avoir exploré la source Django pendant quelques heures, je pense que c'est la solution complète:
Pour supprimer l'option vide (extension de l'exemple de 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
Pour personnaliser l’étiquette d’option vide est essentiellement la même:
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
Je pense que cette approche s'applique à tous les scénarios où ModelChoiceFields sont rendus au format HTML, mais je ne suis pas positif. J'ai constaté que lorsque ces champs sont initialisés, leurs choix sont transmis au widget Sélectionner (voir Django.forms.fields.ChoiceField._set_choices). La définition de empty_label après l'initialisation n'actualise pas la liste de choix du widget Sélectionner. Je ne connais pas suffisamment Django pour savoir si cela doit être considéré comme un bug.
Vous pouvez utiliser ceci sur votre modèle:
class MyModel(models.Model):
name = CharField('fieldname', max_length=10, default=None)
default = None est la réponse: D
NOTE: j'ai essayé ceci sur Django 1.7
Pour ce qui est de Django 1.4, il vous suffit de définir la valeur "par défaut" et "blanc = Faux" dans le champ choix
class MyModel(models.Model):
CHOICES = (
(0, 'A'),
(1, 'B'),
)
choice_field = models.IntegerField(choices=CHOICES, blank=False, default=0)
vous pouvez le faire dans admin:
formfield_overrides = {
models.ForeignKey: {'empty_label': None},
}
Voir ici pour le débat complet et les méthodes de résolution de ce problème.
self.fields['xxx'].empty_value = None
ne fonctionnerait pas si votre type de champ est TypedChoiceField
qui n’a pas la propriété empty_label
.
Ce que nous devrions faire est de supprimer le premier choix:
1 . Si vous voulez créer une BaseForm
auto detect 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. seulement quelques formulaires, vous pouvez utiliser:
class AddClientForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(AddClientForm, self).__init__(*args, **kwargs)
self.fields['xxx'].choices = self.fields['xxx'].choices[1:]
Je déconnais avec cela aujourd'hui et viens de venir avec un lâche bidouille solution astucieuse:
# 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,)
Maintenant, vous pouvez modifier l’étiquette par défaut ModelChoiceField
par tout ce que vous voulez. :-)
PS: Pas besoin de faire l’objet d’un abaissement de voix, les patchs de singe non nocifs sont toujours pratiques.
Pour la dernière version de Django .__, la première réponse devrait être comme ceci
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)`
Pour un champ ForeignKey
, définir la valeur default
sur ''
sur le modèle supprimera l'option vide.
verb = models.ForeignKey(Verb, on_delete=models.CASCADE, default='')
Pour d'autres champs comme CharField
, vous pouvez définir default
sur None
, mais cela ne fonctionne pas pour les champs ForeignKey
dans Django 1.11.
Je trouve la solution !!
Mais pas pour ForeignKey :-)
Peut-être que je peux vous aider… .J'ai consulté le code source de Django et découvert que Django.forms.extras.widgets.SelecteDateWidget () est une propriété appelée none_value qui est égale à (0, '-----'), alors a fait dans mon code cette
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),
}
Cela devient plus compliqué lorsque les choix sont des clés étrangères et si vous souhaitez filtrer les choix en fonction de certains critères. Dans ce cas, si vous définissez le empty_label
puis réaffectez les choix (vous pouvez également appliquer la filtration ici), l’étiquette vide sera vide:
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()
bbasiquement, la première ligne sous init
peut être appliquée à tous les champs du formulaire avec une boucle ou une boucle en ligne:
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
Il y a beaucoup de bonnes réponses ici, mais je ne suis toujours pas entièrement satisfait des implémentations. Je suis aussi un peu frustré que de sélectionner des widgets de différentes sources (clés étrangères, choix) produisent des comportements différents.
Je travaille sur un design dans lequel les champs sélectionnés always ont une option vide, et s’ils sont obligatoires, ils auront une étoile à côté et le formulaire ne sera tout simplement pas validé s’ils sont laissés vides. Cela dit, je ne peux remplacer correctement le empty_label que pour les champs qui ne sont pas TypedChoiceField
s.
Voici à quoi ressemble le résultat devrait. Le premier résultat est toujours le nom du champ - dans mon cas, le label
.
Voici ce que j'ai fini par faire. Voici une méthode __init__
remplacée de mon formulaire:
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]]
Depuis Django 1.7, vous pouvez personnaliser le libellé de la valeur vide en ajoutant une valeur à votre liste de choix dans la définition de votre champ de modèle. De la documentation sur la configuration choix des champs :
Sauf si blank = False est défini sur le champ avec une valeur par défaut, une étiquette contenant "---------" sera rendue avec la zone de sélection. Pour remplacer ce comportement, ajoutez un tuple aux choix contenant aucun; par exemple. (Aucun, 'Votre chaîne à afficher'). Alternativement, vous pouvez utiliser une chaîne vide au lieu de None si cela convient, comme dans un CharField.
J'ai consulté la documentation de différentes versions de Django et constaté qu'il s'agissait de ajouté dans Django 1.7 .