Herramientas de usuario

Herramientas del sitio


wiki2:python:django:forms

Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Próxima revisión
Revisión previa
wiki2:python:django:forms [2018/11/01 08:28]
alfred creado
wiki2:python:django:forms [2020/05/09 09:25] (actual)
Línea 8: Línea 8:
   </​form>​   </​form>​
 </​code>​ </​code>​
 +
 +<​code>​
 +<form method="​post"​ novalidate>​
 +  {% csrf_token %}
 +  {{ form }}
 +  <button type="​submit">​Submit</​button>​
 +</​form>​
 +</​code>​
 +
 +Fíjate aquí, con ''​novalidate''​ no haría la validación de datos local.
  
 <​code>​ <​code>​
Línea 36: Línea 46:
             </​form>​             </​form>​
 </​code>​ </​code>​
 +<​code>​
 +<form method="​post"​ novalidate>​
 +  {% csrf_token %}
  
 +  {{ form.non_field_errors }}
 +
 +  {% for hidden_field in form.hidden_fields %}
 +    {{ hidden_field.errors }}
 +    {{ hidden_field }}
 +  {% endfor %}
 +
 +  <table border="​1">​
 +    {% for field in form.visible_fields %}
 +      <tr>
 +        <​th>​{{ field.label_tag }}</​th>​
 +        <td>
 +          {{ field.errors }}
 +          {{ field }}
 +          {{ field.help_text }}
 +        </td>
 +      </tr>
 +    {% endfor %}
 +  </​table>​
 +
 +  <button type="​submit">​Submit</​button>​
 +</​form>​
 +</​code>​
 +
 +==== How does it work? ====
 +
 +
 +When we write ''<​nowiki>​{{ form }}</​nowiki>''​ in a template, it’s actually accessing the ''<​nowiki>​__str__</​nowiki>''​ method from the BaseForm class. We can use other three methods to render it (as table, as p, as ul tags): as_table(), as_ul(), as_p().
 +
 +The as_table() and as_ul() methods do not create the <​table>​ and the <ul> tags, so we have to add it by ourselves.
 +<​code>​
 +<form method="​post"​ novalidate>​
 +  {% csrf_token %}
 +  <table border="​1">​
 +    {{ form }}
 +  </​table>​
 +  <button type="​submit">​Submit</​button>​
 +</​form>​
 +</​code>​
 +
 +==== The form definition ====
 +<code python>
 +class ColorfulContactForm(forms.Form):​
 +    name = forms.CharField(
 +        max_length=30,​
 +        widget=forms.TextInput(
 +            attrs={
 +                '​style':​ '​border-color:​ blue;',​
 +                '​placeholder':​ 'Write your name here'
 +            }
 +        )
 +    )
 +    email = forms.EmailField(
 +        max_length=254,​
 +        widget=forms.EmailInput(attrs={'​style':​ '​border-color:​ green;'​})
 +    )
 +    message = forms.CharField(
 +        max_length=2000,​
 +        widget=forms.Textarea(attrs={'​style':​ '​border-color:​ orange;'​}),​
 +        help_text='​Write here your message!'​
 +    )
 +</​code>​
 +
 +==== The validation process... ====
 +
 +Converts all the data to proper values in ''​cleaned_data''​ if they are, for sure, valid. An example of a Boolean field:
 +<code python>
 +class MyForm(forms.Form):​
 +    has_code = forms.BooleanField(widget= forms.CheckboxInput())
 +    ​
 +def my_form_view(request):​
 +    if request.method == '​POST':​
 +        my_form = MyForm(request.POST)
 +        if my_form.is_valid():​
 +            # my_form.cleaned_data['​has_code'​] is now a bool
 +</​code>​
 +
 +===== Gotchas =====
 +
 +<code python>
 +unique_together = ('​accounting_year',​ '​number',​)
 +</​code>​
 +===== Widgets =====
 +You can define widgets on for the fields on the same form:
 +<​code>​
 +class PurchaseOrderForm(forms.ModelForm):​
 +    class Meta:
 +        model = PurchaseOrder
 +        fields = '​__all__'​
 +        widgets = {
 +            '​bill_price':​ EuroWidget(),​
 +            '​total_amount':​ EuroWidget(),​
 +        }    ​
 +</​code>​
 +
 +==== Add a widget to a field ====
 +<​code>​
 +city = forms.CharField(widget=forms.TextInput(attrs={'​autocomplete':'​off'​}))
 +</​code>​
 +También lo puedes añadir en el meta:
 +<​code>​
 +'​widgets':​ {'​city':​ forms.TextInput}
 +</​code>​
 +===== Fields =====
 +==== Choice ====
 +=== From DB ===
 +IF you are saving cities into the database, you can use ModelChoiceField:​
 +<​code>​
 +class SelectCityForm(forms.Form):​
 +    cities = forms.ModelChoiceField(queryset=City.objects.all())
 +</​code>​
 +
 +
 +==== Create your own field ====
 +You need the field and the widget:
 +
 +<code python>
 +class SelectMultipleChecks(forms.Widget):​
 +    template_name = '​widgets/​multiple_checks.html'​
 +
 +    def __init__(self,​ *args, choices=(), defaults=(),​ **kwargs):
 +        super().__init__(*args,​ **kwargs)
 +        self.choices = choices
 +
 +    def get_context(self,​ name, value, attrs):
 +        context = super().get_context(name,​ value, attrs)
 +        context['​choices'​] = self.choices
 +        return context
 +
 +
 +class SelectMultipleChecksField(forms.Field):​
 +    widget = SelectMultipleChecks
 +
 +    def __init__(self,​ *args, choices=(), defaults=(),​ **kwargs):
 +        super().__init__(*args,​ **kwargs)
 +        self.choices = choices
 +
 +    def _get_choices(self):​
 +        return self._choices
 +
 +    def _set_choices(self,​ value):
 +        if callable(value):​
 +            value = CallableChoiceIterator(value)
 +        else:
 +            value = list(value)
 +        self._choices = self.widget.choices = value
 +
 +    choices = property(_get_choices,​ _set_choices)
 +
 +    def to_python(self,​ value):
 +        import json
 +        values = json.loads(value)
 +        i_values = [int(v) for v in values]
 +        return [choice for choice in self._choices if choice.pk in i_values]
 +
 +    def validate(self,​ value):
 +        assert len(value) > 0
 +
 +    def valid_value(self,​ value):
 +        return value
 +</​code>​
 +
 +With this we can have the template ''​widgets/​multiple_checks.html'':​
 +<code html>
 +<div style="​display:​ flex; justify-content:​ space-around;">​
 +    <input type="​hidden"​ id="{{ widget.attrs.id }}" value="​[{{ selected|join:","​ }}]">​
 +{% for choice in choices %}
 +    <​div><​input
 +            type="​checkbox"​ {% if choice.pk in selected %}checked{% endif %}
 +            name="​{{widget.attrs.id}}_check"​
 +            data-id="​{{choice.pk}}"​
 +    > {{ choice }}</​div>​
 +{% endfor %}
 +</​div>​
 +</​code>​
 +
 +=== Set rendered properties ===
 +
 +
 +You can set properties to render like this:
 +<​code>​
 +city = forms.CharField(widget=forms.TextInput(attrs={'​autocomplete':'​off'​}))
 +</​code>​
wiki2/python/django/forms.1541060932.txt.gz · Última modificación: 2020/05/09 09:24 (editor externo)