44 votes

Obtenez le type de widget de formulaire Django à partir du modèle.

Je parcours les champs d'un formulaire et pour certains d'entre eux, je souhaite une mise en page légèrement différente, ce qui nécessite une modification du code HTML.

Pour faire cela 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, vous n'êtes pas autorisé à accéder aux variables soulignées dans les modèles. Super !

Vous peut test field.field.widget.input_type mais cela ne fonctionne que pour le texte/mot de passe <input ../> types. 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 des modèles. J'ai externalisé la partie du code qui gère le HTML pour les champs vers un modèle séparé qui est inclus dans la boucle de champ. Cela signifie qu'il est cohérent à travers ModelForm et standard Form (ce qui ne serait pas vrai si j'écrivais une classe Form intermédiaire).

Si vous voyez une approche universelle qui ne m'oblige pas à modifier une vingtaine de formulaires, faites-le moi savoir !

0 votes

Rapport de bogue pertinent ou demande de fonctionnalité : code.djangoproject.com/ticket/13009

43voto

rinti Points 978

La création d'un modèle de balise pourrait fonctionner ? Quelque chose comme field.field.widget|widget_type

Edit d'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 }} rend correctement. Maintenant, je dois juste trouver comment l'utiliser dans un modèle. if déclaration.

Edit d'Oli #2 : J'avais besoin d'utiliser le résultat de cette opération dans un état if dans le modèle, donc j'ai juste déplacé toute cette logique dans le templatetag. Magic. Merci de m'avoir mis dans la bonne direction.

1 votes

Merci pour cette solution. En ce qui concerne l'édition n°2 - avec l'amélioration if tags Dans Django 1.2, vous pouvez effectuer ces comparaisons de types de widgets directement dans le modèle. J'ai posté un exemple dans une réponse séparée.

1 votes

Un autre filtre intéressant à ajouter (si des personnes non-Python sont amenées à manipuler vos modèles) est quelque chose comme ceci, pour les cas les plus utilisés : def is_checkboxes(form_field_obj): return (form_field_obj.__class__.__name__ == "CheckboxSelectMultiple") ... alors vous pouvez faire {% if field|is_checkboxes %} et les gens ne paniqueront pas (...pas de retours)

0 votes

Correction de la fonction définie dans mon dernier commentaire : def is_checkboxes(form_field_obj): return (form_field_obj.field.widget.__class__.__name__ == "CheckboxSelectMultiple")

34voto

zlovelady Points 2572

Suite à la réponse acceptée - l'amélioration if tag dans Django 1.2 vous permet d'utiliser des filtres dans les éléments suivants if tag comparaisons. Ainsi, vous pouvez maintenant faire votre html/logique personnalisé dans le modèle comme suit :

<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>

0 votes

Quel est le but de champ.widget plutôt que d'utiliser simplement champ.widget ?

0 votes

@Wipqozn dans mon expérience field.widget ne produit souvent rien - je n'en suis pas sûr, mais peut-être que ce paramètre n'est défini que si vous le définissez manuellement. field.field.widget travaux.

0 votes

Regardez le field.field informations à la fin de cet article dans les docs

24voto

Ivan Ogai Points 36

À 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 %}

21voto

kret Points 11

Suite à la réponse d'Oli et de rinti : j'ai utilisé celui-ci et je pense qu'il est un peu plus simple :

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

code du filtre :

from django import template
register = template.Library()

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

1voto

BigglesZX Points 408

Il convient peut-être de signaler aux lecteurs contemporains que django-widget-tweaks fournit field_type y widget_type à cette fin, en renvoyant les noms de classe respectifs en minuscules. Dans l'exemple ci-dessous, je montre également la sortie de la fonction input_type sur le widget de champ (depuis Django 1.11), 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 pratiquement tous les cas d'utilisation. Si vous avez besoin de capturer la sortie de l'un de ces filtres pour l'utiliser dans le module if vous pouvez utiliser l'option with étiquette de modèle.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X