web-dev-qa-db-fra.com

Django Formulaires et Bootstrap - Classes CSS et <divs>)

J'utilise Twitter Bootstrap avec Django pour rendre les formulaires.

Bootstrap peut très bien formater vos formulaires, à condition que vous ayez les classes CSS prévues.

Cependant, mon problème est que les formulaires générés par {{ form.as_p }} ne rend pas bien avec Bootstrap, car ils n’ont pas ces classes.

Par exemple, la sortie de Django:

    <form class="horizontal-form" action="/contact/" method="post">
        <div style='display:none'>
            <input type='hidden' name='csrfmiddlewaretoken' 
                   value='26c39ab41e38cf6061367750ea8c2ea8'/>
        </div>
        <p><label for="id_name">Name:</label> <input id="id_name" type="text" name="name" value="FOOBAR" maxlength="20" /></p>
        <p><label for="id_directory">Directory:</label> <input id="id_directory" type="text" name="directory" value="FOOBAR" maxlength="60" /></p>
       <p><label for="id_comment">Comment:</label> <textarea id="id_comment" rows="10" cols="40" name="comment">Lorem ipsum dolor sic amet.</textarea></p>
       <p>
           <label for="id_server">Server:</label>
           <select name="server" id="id_server">
               <option value="">---------</option>
               <option value="1" 
                   selected="selected">sydeqexcd01.au.db.com</option>
               <option value="2">server1</option>
               <option value="3">server2</option>
               <option value="4">server3</option>
           </select>
       </p>
       <input type="submit" value="Submit" />
    </form>

D'après ce que je peux dire, Bootstrap nécessite que vos formulaires aient un <fieldset class="control-group">, chaque <label> a class="control-label", et chaque <input> est enveloppé dans un <div>:

<fieldset class="control-group">
    <label class="control-label" for="input01">Text input</label>
    <div class="controls">
        <input type="text" class="xlarge" name="input01">
        <p class="help-text">Help text here. Be sure to fill this out like so, or else!</p>
    </div>
</fieldset>

Cependant, ajouter des étiquettes CSS personnalisées à chaque champ de formulaire dans Django est plutôt pénible:

Ajouter une classe à la sortie Django label_tag () output

Existe-t-il un moyen plus intelligent d’utiliser {{ form.as_p }}, ou en parcourant les champs, sans avoir à spécifier manuellement les choses, ou à faire tout un tas de hackery?

À la vôtre, Victor

65
victorhooi

J'aime utiliser "Django-crispy-forms" qui est le successeur de Django-uni-form. C'est une excellente petite API et supporte parfaitement Bootstrap.

J'ai tendance à utiliser les filtres de modèle pour porter rapidement du code ancien et des formulaires rapides, ainsi que les balises de modèle lorsque j'ai besoin de plus de contrôle sur le rendu.

47
erikcw

Voici ce que je suis venu avec:

<form class="form-horizontal" method="post">{% csrf_token %}
    <fieldset>
        <legend>{{ title }}</legend>
        {% for field in form %}
            {% if field.errors %}
                <div class="control-group error">
                    <label class="control-label">{{ field.label }}</label> 
                    <div class="controls">{{ field }}
                        <span class="help-inline">
                            {% for error in  field.errors %}{{ error }}{% endfor %}
                        </span>
                    </div>
                </div>
            {% else %}
                <div class="control-group">
                    <label class="control-label">{{ field.label }}</label> 
                    <div class="controls">{{ field }}
                        {% if field.help_text %}
                            <p class="help-inline"><small>{{ field.help_text }}</small></p>
                        {% endif %}
                    </div>
                </div>
            {% endif %}
        {% endfor %}
    </fieldset>
    <div class="form-actions">
        <button type="submit" class="btn btn-primary" >Submit</button>
    </div>
</form>
52
jcmrgo

Quand Django-crispy-forms _ ne peut pas être utilisé (par exemple, lorsque le modèle traite individuellement chaque champ du formulaire), la réponse de jcmrgo est la seule solution. Basé sur sa réponse, voici une solution pour Bootstrap 3 (laissant sa version pour Boostrap 2), et avec ajustement des classes de champs à l'intérieur du modèle . Bien que les classes de champs ne soient pas accessibles depuis le modèle avec la bibliothèque standard de Django (ce qui conduit à des formulaires supplémentaires ou des balises de modèles dans d'autres solutions), voici une solution qui définit les bonnes classes en balises de champs sans avoir à coder en dehors du modèle:

{% load i18n widget_tweaks %}

<form class="form-horizontal" role="form" action="." method="post">
    {% csrf_token %}
    {% for field in form %}
        {% if field.errors %}
            <div class="form-group has-error">
                <label class="col-sm-2 control-label" for="id_{{ field.name }}">{{ field.label }}</label>
                <div class="col-sm-10">
                    {{ field|attr:"class:form-control" }}
                    <span class="help-block">
                        {% for error in  field.errors %}{{ error }}{% endfor %}
                    </span>
                </div>
            </div>
        {% else %}
            <div class="form-group">
                <label class="col-sm-2 control-label" for="id_{{ field.name }}">{{ field.label }}</label>
                <div class="col-sm-10">
                    {{ field|attr:"class:form-control" }}
                    {% if field.help_text %}
                        <p class="help-block"><small>{{ field.help_text }}</small></p>
                    {% endif %}
                </div>
            </div>
        {% endif %}
    {% endfor %}
    <div class="form-group">
        <div class="col-sm-offset-2 col-sm-10">
            <button type="submit" class="btn btn-primary">{% trans "Submit" %}</button>
        </div>
    </div>
</form>

Cela nécessite Django-widget-tweaks installé et widget_tweaks ajouté à INSTALLED_APPS .

38
Iodnas

Vous pouvez faire quelque chose comme ça:

{% for field in form %}
<fieldset class="control-group">
    <label class="control-label" for="id_{{ field.name }}">{{ field.label }}</label>
    <div class="controls">
        {{ field }}
        <p class="help-text">{{ field.help_text }} </p>
    </div>
</fieldset>
{% endfor %}
10
c4urself

Pour ajouter des attributs CSS à Django a généré des formulaires, il suffit d’utiliser le code suivant dans votre forms.py:

Recepient = forms.ChoiceField(label=u'Recepient', widget=forms.Select(attrs={'id':'combobox'}))

Il produira le code HTML suivant:

<label for="id_Recepient">Recepient</label>
<select id="combobox" name="Recepient">
8
Jaro
4
bogtan

Voici ma version utilisant Django_tweaks avec un meilleur résultat. Je trouve render_field plus léger à utiliser que l'ajout de filtres. J'ai également ajouté bootstrap des messages d'alerte formatés et désactivé la validation du navigateur (avec novalidate). Je suis relativement nouveau sur Django, alors n'hésitez pas à commenter si vous trouvez un non-sens

<form class="large" method="post" action="/suscript/" novalidate>
    {% csrf_token %}
    <fieldset>
        <legend>{{ title }}</legend>
        {% for field in form %}
            <div class="control-group {%if field.errors %}error{%endif%}">
                <div class="input-group controls">
                    <label class="input-group-addon control-label" id="{{field.label|safe}}">{{ field.label }}</label>
                    {% render_field field type="text" class="form-control" placeholder="" aria-describedby="field.label|safe" %}
                </div>
                    {% for error in field.errors %}
                         <div class="alert alert-danger">
                            <strong>{{ error|escape }}</strong>
                         </div>
                    {% endfor %}

                    {% if field.help_text %}
                        <p class="help-inline">{{ field.help_text|safe }}</p>
                    {% endif %}
            </div>

        {% endfor %}
    </fieldset>
    <div class="form-actions">
        <button type="submit" class="btn btn-primary" >Submit</button>
    </div>
</form>
3

Par exemple, vous pouvez créer une classe qui définit les attributs comme vous le souhaitez et appelez-la en conséquence.

class ContactForm(ModelForm):
    class Meta:
      model = Contact
      created = MyDatePicker()

class Uniform(forms):
  def __init__(self, *args, **kwargs):
      attrs = kwargs.pop("attrs",{})
      attrs["class"] = "span3"
      kwargs["attrs"] = attrs
      super(Uniform, self).__init__(*args, **kwargs)

class MyDatePicker(Uniform,forms.DateInput)
  def __init__(self, *args, **kwargs):
      attrs = kwargs.pop("attrs",{})
      attrs["class"] = "datepick" 
      attrs["id"] =kwargs.get('datetag', '')
      kwargs["attrs"] = attrs
      super(MyDatePicker, self).__init__(*args, **kwargs)
3
lakesh

Les styles de bootstrap avec <div>s plutôt que <p>s. Donc, si vous voulez que ça ait l'air bien, vous devez y aller bootstrap façon 100% à mon humble avis. Et voici ma façon préférée de le faire:

Utilisez Django-bootstrap app. Exemple:

{% load bootstrap3 %}

<form class="signup form-horizontal" id="signup_form" method="post" action="{% url 'account_signup' %}">
    {% csrf_token %}
    {% bootstrap_form form layout="horizontal" %}
    {% buttons submit='Sign Up &raquo;' reset='Reset Form' layout='horizontal' %}{% endbuttons %}
</form>

Remarquez l'attribut horizontal in 1) de la classe de formulaire 2) la disposition bootstrap_form et la disposition 3) des boutons.

3
mehmet

Le moyen le plus rapide et le plus simple serait de définir votre propre classe de base qui étend la classe Django Form, et de redéfinir sa as_p la méthode de sortie au format Bootstrap nécessite. Ensuite, modifiez vos formulaires pour qu'ils héritent de votre nouvelle classe Form au lieu de ceux de Django.

2
user719958

outre ce que d'autres amis ont dit, je vous recommanderais d'utiliser 'Django-widget-tweaks'.

la réponse serait comme ça:

{% for field in form %}
      <label for="{{ field.label }}">{{ field.label }}</label>
      {{ field|add_class:"form-control" }}
      <span class="error-block">{{ field.errors }}</span>
{% endfor %}
0
Lord ST