Personalizando como uma forma gera um campo para um widget no Django

votos
3

Eu tenho um campo personalizado chamado HourField, que permite que você digite 1:30 para representar uma hora e meia. O clean()método transforma-lo em 1,5 para o FloatField no modelo. Isso tudo funciona bem. Agora eu estou tendo um problema onde quando eu quero criar um formset, esse campo é renderizado como 1,5 em vez de 01:30, que é o que eu quero.

Existe algum tipo de método semelhante ao clean(), mas funciona de outra maneira ao redor?

edit: usando outro tipo de método de armazenamento está fora de questão. Eu tenho alguns outros campos personalizados que eu fiz, que são armazenados como um tipo de objeto, mas são inseridos pelo usuário como uma string. I utilizado o exemplo acima, uma vez que era o mais para a frente em linha reta.

Publicado 27/08/2009 em 08:02
fonte usuário
Em outras línguas...                            


4 respostas

votos
3

Para personalizar a forma como um campo torna, você precisa definir um widget bem.

O código a seguir mostra algumas responsabilidades de widgets em Django:

  • tornar o tag form (superclasse TextInput cuida disso)
  • formatar o valor para exibir dentro do campo de formulário. há uma pegadinha aqui: classe do valor pode variar, desde que você pode tornar valores limpos provenientes do campo, ou dados contaminadas provenientes de um POST formulário. Daí o teste, se temos um valor numérico no _format_value; se é uma string, basta deixá-lo como está.
  • dizer se o valor foi alterado, em comparação com os dados iniciais. Muito importante quando você usa formsets com valores padrão.

Por favor, note que o código do widget é inspirado por widgets.TimeInput do código fonte do Django, o que ajuda a ser coerente.

from django import forms
from django.forms import widgets
from django.forms.util import ValidationError

class HourWidget(widgets.TextInput):

    def _format_value(self, value):
        if isinstance(value, float) or isinstance(value, int):
            import math

            hours = math.floor(value)
            minutes = (value - hours) * 60
            value = "%d:%02d" % (hours, minutes)

        return value

    def render(self, name, value, attrs=None):
        value = self._format_value(value)
        return super(HourWidget, self).render(name, value, attrs)

    def _has_changed(self, initial, data):
        return super(HourWidget, self)._has_changed(self._format_value(initial), data)

class HourField(forms.Field):
    widget = HourWidget

    def clean(self, value):
        super(HourField, self).clean(value)

        import re
        match = re.match("^([0-9]{1,2}):([0-9]{2})$", value)
        if not match:
            raise ValidationError("Please enter a valid hour ( ex: 12:34 )")

        groups = match.groups()
        hour = float(groups[0])
        minutes = float(groups[1])

        if minutes >= 60:
            raise ValidationError("Invalid value for minutes")

        return hour + minutes/60

Por favor note que se torna 01:20 01:19, que é devido à perda de precisão induzida pelo uso de uma bóia. Você pode querer alterar o tipo de dados se você não quer perder alguma precisão.

Respondeu 31/08/2009 em 00:43
fonte usuário

votos
1
from django.forms.widgets import TextInput

class TimeInput(TextInput):
     def _format_value(self, value):
         """Convert float to time"""
         if not value:
             return ''
         fraction, integer = math.modf(value)
         minutes = 0 if fraction == 0 else .6 / fraction
         return "%d:%02d" % (int(integer), int(minutes))

     def render(self, name, value, attrs=None):
        value = self._format_value(value)
        return super(TimeInput, self).render(name, value, attrs)
Respondeu 30/08/2009 em 04:09
fonte usuário

votos
1

Como os dados são exibidos em um campo de formulário é de responsabilidade do widget. Parece que você precisará definir um widget personalizado que implementa um render()método que leva o valor do campo decimal e envia-lo como quiser.

Infelizmente não parece ser qualquer documentação sobre a criação de widgets personalizados, mas você pode olhar para o código django.forms.extras.widgetspara um exemplo de como fazê-lo.

Respondeu 27/08/2009 em 10:49
fonte usuário

votos
0

Eu acho que você pode querer experimentar com a tag data ou, eventualmente, criar a sua própria marca de modelo. Esta é band-aid though- a verdadeira questão é que você deve armazenar esse tempo em Python como um tempo usando o módulo datetime. Isso irá garantir que ele está formatado bem.

Respondeu 27/08/2009 em 08:28
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more