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

Ambos lados, revisión anterior Revisión previa
Próxima revisión
Revisión previa
wiki2:python:django:forms [2018/11/10 17:47]
alfred
wiki2:python:django:forms [2020/05/09 09:25] (actual)
Línea 47: Línea 47:
 </​code>​ </​code>​
 <​code>​ <​code>​
-# In form_snippet.html: +<form method="​post"​ novalidate>​ 
-{% for field in form %} +  {% csrf_token %} 
-    <div class="fieldWrapper">​ + 
-        {{ field.errors ​}} +  {{ form.non_field_errors }} 
-        {{ field.label_tag ​}} {{ field }} + 
-    </​div>​+  {% 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 %} {% 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>​ </​code>​
wiki2/python/django/forms.1541872048.txt.gz · Última modificación: 2020/05/09 09:24 (editor externo)