Измените виджет только одного поля в django-crispy-forms с помощью объекта макета AppendedText

Я использую django-crispy-forms для отображения формы модели в django. django-crispy-forms уже очень хорошо интегрируется с Twitter Bootstrap и определил объект макета для AppendedText виджет:

Виджет с добавленным текстом

У меня есть следующая модель в моем 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)

и я определяю следующие modelform в 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'))

Мой вопрос заключается в том, как я могу изменить виджет поля peso без создания нового подкласса widget, поскольку django-crispy-forms уже определяет объект макета. Также обратите внимание, что я не хочу перечислять все остальные поля, чтобы сделать это так:

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

так как мне придется продолжать редактировать макет помощника, если я решу добавить новые поля в свою модель, из которых стандартные виджеты уже очень полезны.

Редактировать: я также видел методы доступа к макетам в помощнике, таком как self.helper.layout[0] = AppendedText('peso', 'kg'), но я не знаю индекс поля, которое я хотел бы изменить, и было бы намного лучше, если бы я мог просто написать self.helper.layout['peso'] = AppendedText('peso', 'kg')


person Gustavo Torres    schedule 17.03.2013    source источник


Ответы (2)


У django-crispy-forms есть API для таких вещей: http://django-crispy-forms.readthedocs.org/en/latest/dynamic_layouts.html

Вы можете просто сделать:

form.helper['peso'].wrap(AppendedText, "kg")
person maraujop    schedule 24.03.2013
comment
Это работает с небольшим изменением form.helper['peso'].wrap(AppendedText, "peso", "kg"). Спасибо! - person Gustavo Torres; 25.03.2013
comment
Извините, Густаво, но то, что вы указали, является ошибкой. Вам не нужно передавать имя поля. Как и в других случаях, когда вы оборачиваете несколько полей, нет возможности передать имена полей для всех из них. Это было исправлено в этой фиксации github.com/maraujop/django-crispy-forms. /commit/ и будет частью хрустящих форм 1.2.5 - person maraujop; 14.04.2013
comment
Это все еще дает мне ошибку You need to set a layout in your FormHelper, но я не хочу, потому что я не могу ссылаться на каждое поле в макете. Мне также придется пойти и изменить его, если я добавлю больше полей. - person jozxyqk; 21.07.2015

Хорошо, это то, что сработало для меня, не будучи слишком многословным и сохраняя простоту. В методе __init__ просто сделайте следующее:

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

Это отлично работает, если поле, которое вы ищете, находится на первом уровне иерархии в объекте layout, в противном случае вам нужно было бы более конкретно указать, что вы ищете. Например, если ваше поле находится в контейнере DIV, вам сначала нужно будет проверить, находится ли field.__class__ == DIV, а затем проанализировать поле DIV, что не так просто, как кажется.

Однако было бы неплохо иметь API объекта layout для поддержки фильтрующих запросов.

person Gustavo Torres    schedule 17.03.2013