Herramientas de usuario

Herramientas del sitio


wiki2:python:django:forms

¡Esta es una revisión vieja del documento!


Django Forms

Render a form

  <form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Sign up</button>
  </form>
<form method="post" novalidate>
  {% csrf_token %}
  {{ form }}
  <button type="submit">Submit</button>
</form>

Fíjate aquí, con novalidate no haría la validación de datos local.

   <form method="post" action="{% url 'login' %}">
    {% csrf_token %}

    <div>
      <td>{{ form.username.label_tag }}</td>
      <td>{{ form.username }}</td>
    </div>
    <div>
      <td>{{ form.password.label_tag }}</td>
      <td>{{ form.password }}</td>
    </div>
    <div>
      <input type="submit" value="login" />
      <input type="hidden" name="next" value="{{ next }}" />
    </div>
    </form>
            <form action="{% url 'login' %}" method="POST">
                {% csrf_token %}
                <input type="text" name="username" placeholder="Username">
                <input type="password" name="password" placeholder="Password">
                <input type='submit' value='login'>
            </form>
<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>

How does it work?

When we write {{ form }} in a template, it’s actually accessing the __str__ 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.

<form method="post" novalidate>
  {% csrf_token %}
  <table border="1">
    {{ form }}
  </table>
  <button type="submit">Submit</button>
</form>

The form definition

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!'
    )

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:

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

Gotchas

unique_together = ('accounting_year', 'number',)

Widgets

You can define widgets on for the fields on the same form:

class PurchaseOrderForm(forms.ModelForm):
    class Meta:
        model = PurchaseOrder
        fields = '__all__'
        widgets = {
            'bill_price': EuroWidget(),
            'total_amount': EuroWidget(),
        }    

Fields

Choice

From DB

IF you are saving cities into the database, you can use ModelChoiceField:

class SelectCityForm(forms.Form):
    cities = forms.ModelChoiceField(queryset=City.objects.all())

Create your own field

You need the field and the widget:

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

With this we can have the template widgets/multiple_checks.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>
wiki2/python/django/forms.1552206429.txt.gz · Última modificación: 2020/05/09 09:24 (editor externo)