Question

I am using django-crispy-forms to render the form of a model in django. django-crispy-forms already integrates very well with Twitter Bootstrap and has defined a layout object for the AppendedText widget:

AppendedText widget

I have the following model in my django models.py

class Historia(models.Model):
    persona         = models.ForeignKey('Persona', 
                                  blank=False, 
                                  null=True,
                                  related_name='historias')
    fecha           = models.DateTimeField(unique=True, 
                                auto_now_add=True)
    motivo          = models.TextField()
    peso            = models.DecimalField(blank=True,
                                   max_digits=5, decimal_places=2)
    talla           = models.IntegerField(blank=True)
    tension         = models.CharField(max_length=15)
    pulso           = models.IntegerField()
    diagnostico     = models.TextField()
    tratamiento     = models.TextField()
    pendiente       = models.TextField(blank=True)

and I define the following modelform in forms.py:

class HistoriaForm(django.forms.ModelForm):
    class Meta:
        model = models.Historia

    def __init__(self, *args, **kwargs):
        super(HistoriaForm, self).__init__(*args, **kwargs)

        self.helper = FormHelper(self)
        self.helper.form_class = 'form-horizontal'
        self.helper.form_tag = True
        self.helper.form_id = 'nueva_historia_form'
        self.helper.form_action = 'nueva_historia'

        self.helper.form_show_errors = True
        self.helper.error_text_inline = False

        self.helper.add_input(Submit('crear', 'Crear'))

My question is how can I change the widget of the peso field without having to create a new widget subclass since django-crispy-forms already defines a layout object. Please also note that I do not want to enumerate all other fields in order to do this like:

self.helper.layout = Layout(
            Fieldset(
                'Legend',
                'nombre',
                'apellido',
                AppendedText('peso', 'kg')
            ),
            ButtonHolder(
                Submit('submit', 'Submit', css_class='button white')
            )
        )

since I will have to keep editing the helper layout if I decide to add new fields in my model from which standard widgets are already very useful.

Edit: I have also seen the methods to access the layouts in a helper like self.helper.layout[0] = AppendedText('peso', 'kg') but I do not know the index of the field I would like to change and it would be much nicer if I could just write self.helper.layout['peso'] = AppendedText('peso', 'kg')

Was it helpful?

Solution

django-crispy-forms does have an API for these kind of things: http://django-crispy-forms.readthedocs.org/en/latest/dynamic_layouts.html

You could simply do:

form.helper['peso'].wrap(AppendedText, "kg")

OTHER TIPS

Ok, this is what worked for me without having to be too verbose and keeping it simple. In the __init__ method just do the following:

for i, field in enumerate(self.helper.layout):
    if field == 'peso':
        self.helper.layout[i] = AppendedText('peso', 'kg')

This works perfectly fine if the field you are looking for is in the first level of hierarchy in the layout object, otherwise you would have to be more specific about what you are looking. For example if your field is in a DIV container you would first will have to check whether field.__class__ == DIV and then introspect into the DIV field which is not as easy as it seems.

It would be nice, however, to have the API of the layout object to support filter queries

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top