formularios form fields example avanzados python django django-models django-forms

python - form - post django



Personalizar/eliminar la opciĆ³n Django seleccionar cuadro en blanco (14)

¡¡¡ENCUENTRO SOLUCIÓN

Pero no para ForeignKey :-)

Quizás pueda ayudarte. Busqué en el código fuente de Django y descubrí que en django.forms.extras.widgets.SelecteDateWidget () es una propiedad llamada none_value que equivale a (0, ''-----'') así que lo hice en mi código este

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), }

Estoy usando Django 1.0.2. He escrito un ModelForm respaldado por un modelo. Este modelo tiene una ForeignKey en blanco = Falso. Cuando Django genera HTML para este formulario, crea un cuadro de selección con una opción para cada fila en la tabla a la que hace referencia ForeignKey. También crea una opción en la parte superior de la lista que no tiene ningún valor y se muestra como una serie de guiones:

<option value="">---------</option>

Lo que me gustaría saber es:

  1. ¿Cuál es la forma más limpia de eliminar esta opción generada automáticamente del cuadro de selección?
  2. ¿Cuál es la forma más limpia de personalizarlo para que se muestre como:

    <option value="">Select Item</option>

Al buscar una solución, me encontré con el ticket 4652 de Django, que me dio la impresión de que otros tenían la misma pregunta y que el comportamiento predeterminado de Django podría haberse modificado. Este boleto tiene más de un año, así que esperaba que hubiera una manera más limpia de lograr estas cosas.

Gracias por cualquier ayuda,

Jeff

Editar: configuré el campo ForeignKey como tal:

verb = models.ForeignKey(Verb, blank=False, default=get_default_verb)

Esto establece el valor predeterminado para que ya no sea la opción vacía / guiones, pero desafortunadamente no parece resolver ninguna de mis preguntas. Es decir, la opción vacía / guiones aún aparece en la lista.


Aquí hay muchas respuestas excelentes, pero aún no estoy del todo satisfecho con las implementaciones. También estoy un poco frustrado de que los widgets seleccionados de diferentes fuentes (claves externas, elecciones) produzcan comportamientos diferentes.

Tengo un diseño con el que estoy trabajando, en el que los campos seleccionados siempre tienen una opción en blanco, y si son necesarios, tendrán una estrella junto a ellos y el formulario simplemente no se validará si se dejan en blanco. Dicho esto, solo puedo anular correctamente la etiqueta empty_ para campos que no son TypedChoiceField .

Este es el aspecto que debería tener el resultado. El primer resultado es siempre el nombre del campo, en mi caso, la label .

Esto es lo que terminé haciendo. El siguiente es un método __init__ anulado de mi formulario:

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]]


Con la respuesta de Carl como guía y después de rootear la fuente de Django durante un par de horas, creo que esta es la solución completa:

  1. Para eliminar la opción vacía (extendiendo el ejemplo 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

  2. Para personalizar la etiqueta de opción vacía es esencialmente la misma:

    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

Creo que este enfoque se aplica a todos los escenarios donde ModelChoiceFields se representan como HTML, pero no soy positivo. Descubrí que cuando estos campos se inicializan, sus opciones se pasan al widget Seleccionar (consulte django.forms.fields.ChoiceField._set_choices). Establecer la etiqueta empty_ después de la inicialización no actualiza la lista de opciones del widget Seleccionar. No estoy lo suficientemente familiarizado con Django para saber si esto debería considerarse un error.


Desde Django 1.7, puede personalizar la etiqueta para el valor en blanco agregando un valor a su lista de opciones en la definición de campo de su modelo. De la documentación sobre la configuración de opciones de campo :

A menos que esté en blanco = False en el campo junto con un valor predeterminado, se mostrará una etiqueta que contenga "---------" con el cuadro de selección. Para anular este comportamiento, agregue una tupla a las opciones que contengan Ninguno; ej. (Ninguno, ''Su cadena para mostrar''). Alternativamente, puede usar una cadena vacía en lugar de None cuando esto tenga sentido, como en un CharField.

Revisé la documentación de las diferentes versiones de Django y encontré que esto se agregó en Django 1.7 .


En cuanto a django 1.4, todo lo que necesita es establecer el valor "predeterminado" y "blanco = falso" en el campo de opciones

class MyModel(models.Model): CHOICES = ( (0, ''A''), (1, ''B''), ) choice_field = models.IntegerField(choices=CHOICES, blank=False, default=0)


Estuve jugando con esto hoy y me encontré con una solución ingeniosa para hackear cobardes :

# 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,)

Ahora puede ajustar la etiqueta vacía de ModelChoiceField defecto a cualquier cosa que desee. :-)

PD: No hay necesidad de downvotes, parches de mono no dañinos siempre son útiles.


No lo he probado, pero basado en leer el código de Django here y here creo que debería funcionar:

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

EDITAR : Esto está documented , aunque no necesariamente sabrá buscar ModelChoiceField si está trabajando con un ModelForm generado automáticamente.

EDITAR : Como jlpp notas en su respuesta, esto no está completo - tienes que reasignar las elecciones a los widgets después de cambiar el atributo empty_label. Ya que es un poco raro, la otra opción que podría ser más fácil de entender es simplemente anular todo el ModelChoiceField:

class ThingForm(models.ModelForm): verb = ModelChoiceField(Verb.objects.all(), empty_label=None) class Meta: model = Thing


Para la última versión de django, la primera respuesta debería ser así

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)`


Para un campo ForeignKey , establecer el valor default en '''' en el modelo eliminará la opción en blanco.

verb = models.ForeignKey(Verb, on_delete=models.CASCADE, default='''')

Para otros campos como CharField , puede establecer el default en None , pero esto no funciona para los campos ForeignKey en Django 1.11.


Puedes usar esto en tu modelo:

class MyModel(models.Model): name = CharField(''fieldname'', max_length=10, default=None)

predeterminado = ninguna es la respuesta: D

NOTA: Intenté esto en Django 1.7


Vea aquí el debate completo y los métodos para resolver este problema.


de los documentos

La opción en blanco no se incluirá si el campo del modelo tiene en blanco = Falso y un valor predeterminado explícito (el valor predeterminado se seleccionará inicialmente en su lugar).

así que establece el valor predeterminado y estás bien


puedes hacer esto en admin:

formfield_overrides = { models.ForeignKey: {''empty_label'': None}, }


self.fields[''xxx''].empty_value = None no funcionaría si tu tipo de campo es TypedChoiceField que no tiene la propiedad empty_label .

Lo que debemos hacer es eliminar la primera opción:

1. Si desea construir un BaseForm auto detectar 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. solo algunos formularios, puede usar:

class AddClientForm(forms.ModelForm): def __init__(self, *args, **kwargs): super(AddClientForm, self).__init__(*args, **kwargs) self.fields[''xxx''].choices = self.fields[''xxx''].choices[1:]