web-dev-qa-db-fra.com

Obtenez le type de widget de formulaire Django à partir d'un modèle

Je parcourt les champs d'un formulaire et, pour certains champs, je souhaite une disposition légèrement différente, nécessitant une modification du code HTML.

Pour le faire avec précision, j'ai juste besoin de connaître le type de widget. Son nom de classe ou quelque chose de similaire. En python standard, c'est facile! field.field.widget.__class__.__name__

Malheureusement, l'accès aux variables de soulignement dans les modèles n'est pas autorisé. Génial!

Vous pouvez tester field.field.widget.input_type mais cela ne fonctionne que pour les types text/password <input ../>. J'ai besoin de plus de résolution que ça.

Pour moi, aussi difficile que cela puisse paraître, il est plus logique de le faire au niveau du modèle. J'ai externalisé le code qui gère HTML pour les champs dans un modèle séparé, inclus dans la boucle de champ. Cela signifie qu'il est cohérent entre ModelForms et les Forms standard (ce qui ne serait pas le cas si j'écrivais une classe de formulaire intermédiaire).

Si vous pouvez voir une approche universelle qui ne nécessite pas que je modifie une vingtaine de formulaires, faites-le moi savoir aussi!

40
Oli

À partir de Django 1.11, vous pouvez simplement utiliser widget.input_type. Exemple:

{% for field in form.visible_fields %}
    <input type="{{ field.field.widget.input_type }}"
           id="{{ field.id_for_label }}"
           name="{{ field.html_name }}"
           placeholder="{{ field.label }}"
           maxlength="{{ field.field.max_length }}" />
{% endfor %}
13
Ivan Ogai

Faire une balise de modèle pourrait fonctionner? Quelque chose comme field.field.widget|widget_type

Edit de Oli: Bon point! Je viens d'écrire un filtre:

from Django import template
register = template.Library()

@register.filter('klass')
def klass(ob):
    return ob.__class__.__name__

Et maintenant, {{ object|klass }} s'affiche correctement. Maintenant, je viens de comprendre comment utiliser cela dans la déclaration if d'un modèle.

Edit from Oli # 2: je devais utiliser le résultat de cela dans un template de déclaration de if, alors je viens de déplacer toute cette logique dans le template. La magie. Merci de m'avoir poussé dans la bonne direction.

43
rinti

Pour faire suite à la réponse acceptée - le if tag amélioré dans Django 1.2 vous permet d’utiliser des filtres dans les comparaisons if tag. Ainsi, vous pouvez maintenant créer votre code HTML/logique personnalisé dans le modèle de la manière suivante:

<ul>
{% for field in form.fields %}
  <li>
    {% if field.field.widget|klass == "Textarea" %}
    <!-- do something special for Textarea -->
    <h2>Text Areas are Special </h2>
    {% else %}      
      {{ field.errors }}
      {{ field.label_tag }}
      {{ field }}
    {% endif %}

  </li>
{% endfor %}
</ul>
35
zlovelady

Suite à la réponse de Oli et rinti: J'ai utilisé celui-ci et je pense que c'est un peu plus simple:

code du modèle: {{ field|fieldtype }}

code de filtre: 

from Django import template
register = template.Library()

@register.filter('fieldtype')
def fieldtype(field):
    return field.field.widget.__class__.__name__
17
Piotr Szachewicz

Cela vaut peut-être la peine de signaler aux lecteurs contemporains que Django-widget-tweaks fournit les filtres de modèle field_type et widget_type à cette fin, renvoyant les noms de classe respectifs en minuscule. Dans l'exemple ci-dessous, je montre également la sortie de la propriété input_type sur le widget de champ (depuis Django 1.11), ce qui peut également être utile.

forms.py:

class ContactForm(forms.Form):
    name = forms.CharField(
        max_length=150,
        required=True,
        label='Your name'
    )

template.html:

{% load widget_tweaks %}

{% for field in form.visible_fields %}
{{ field.label }}
{{ field.field.widget.input_type }}
{{ field|field_type }}
{{ field|widget_type }})
{% endfor %}

Résultat:

Your name
text
charfield
textinput

Entre ces différentes options, vous devriez pouvoir trouver la bonne propriété à cibler pour n'importe quel cas d'utilisation. Si vous devez capturer la sortie de l'un de ces filtres pour l'utiliser dans les instructions if, vous pouvez utiliser la balise with template.

0
BigglesZX