Django: Comment ajouter des attributs html arbitraires aux champs d'entrée d'un formulaire?

101

J'ai un champ d'entrée qui est rendu avec un modèle comme ceci:

<div class="field">
   {{ form.city }}
</div>

Qui est rendu comme:

<div class="field">
    <input id="id_city" type="text" name="city" maxlength="100" />
</div>

Supposons maintenant que je veuille ajouter un autocomplete="off"attribut à l'élément d'entrée qui est rendu, comment ferais-je cela? Ou onclick="xyz()"ou class="my-special-css-class"?

Utilisateur
la source

Réponses:

126

Consultez cette page

city = forms.CharField(widget=forms.TextInput(attrs={'autocomplete':'off'}))
Galien
la source
2
D'accord, merci. Dans mon cas, j'utilise ModelForm donc je ne définis pas explicitement les champs du formulaire (par exemple, la classe AddressForm (forms.ModelForm): class Meta: model = models.Address) Cela signifie-t-il que je ne peux pas utiliser ModelForm ou y a-t-il quelque chose de spécial? besoin de faire?
Utilisateur
1
ok Nevermind, rtfm: docs.djangoproject.com/en/dev/topics/forms/modelforms
Utilisateur
1
@InfinatelyLoopy dans le formulaire init for, vous pouvez ajouter du code pour saisir le champ et modifier les attributs de ses widgets. En voici quelques-uns que j'ai utilisés précédemment pour modifier 3 champs: `` `` for field_name in ['image', 'image_small', 'image_mobile']: field = self.fields.get (field_name) field.widget.attrs ['data- file '] =' file '`` ``
Stuart Axon
4
Qu'en est-il des attributs qui ne prennent pas d'arguments tels que «requis» et «autofocus»?
Wilhelm Klopp
1
Cette solution est mauvaise car il n'y a pas de séparation des préoccupations. Les attributs HTML ne doivent pas être écrits en code python IMO. La solution Mikhail Korobov est supérieure.
David D.
115

Désolé pour la publicité, mais j'ai récemment publié une application ( https://github.com/kmike/django-widget-tweaks ) qui rend ces tâches encore moins pénibles afin que les concepteurs puissent le faire sans toucher au code Python:

{% load widget_tweaks %}
...
<div class="field">
   {{ form.city|attr:"autocomplete:off"|add_class:"my_css_class" }}
</div>

Ou bien,

{% load widget_tweaks %}
...
<div class="field">
   {% render_field form.city autocomplete="off" class+="my_css_class" %}
</div>
Mikhail Korobov
la source
3
Belle application Mike, exactement ce que je cherchais!
jmagnusson
la documentation ne vous dit pas d'ajouter "widget_tweaks" dans votre application installée dans les paramètres, cela pourrait valoir la peine de le mettre dans la documentation.
James Lin
Salut James, ce n'est pas souligné mais dans la section 'Installation' il y a déjà une note sur l'ajout de 'widget_tweaks' à INSTALLED_APPS.
Mikhail Korobov
@MikhailKorobov merci beaucoup pour cette application, cela m'a beaucoup aidé! C'était juste la bonne chose que je cherchais. J'avais besoin d'un formulaire de ModelForm et je ne voulais pas insérer manuellement ces attributs dans chaque champ (40 d'entre eux), donc j'ai élégamment réussi à obtenir le même résultat en quelques secondes :) Cela devrait être la réponse acceptée!
Ljubisa Livac
J'avais l'intention d'écrire une telle application. Merci d'avoir économisé mes efforts.
Anuj TBE
31

Si vous utilisez "ModelForm":

class YourModelForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(YourModelForm, self).__init__(*args, **kwargs)
        self.fields['city'].widget.attrs.update({
            'autocomplete': 'off'
        })
Artificioo
la source
3
Bien! Pas besoin de définir explicitement tous les widgets maintenant.
Mikael Lindlöf
20

Si vous utilisez ModelForm, outre la possibilité d'utiliser __init__comme @Artificioo fournie dans sa réponse, il existe un widgetsdictionnaire dans Meta d'ailleurs:

class AuthorForm(ModelForm):
    class Meta:
        model = Author
        fields = ('name', 'title', 'birth_date')
        widgets = {
            'name': Textarea(attrs={'cols': 80, 'rows': 20}),
        }

Documentation pertinente

Wtower
la source
1
Essayer de comprendre pourquoi cela a reçu moins de votes positifs que la réponse ci-dessus ... parfois, je pense que les développeurs Django / Python préfèrent simplement la manière la plus difficile de faire les choses ...
trpt4him
@ trpt4him L'utilisation de l' approche init est utile pour créer un mixin ou une classe de base que vous pouvez réutiliser dans d'autres formulaires. C'est typique dans un projet de moyenne à grande échelle. Le Meta.widgets est idéal pour un seul formulaire. Donc, les deux sont de bonnes réponses.
Akhorus le
3

Je ne voulais pas utiliser une application entière pour cette chose. Au lieu de cela, j'ai trouvé le code suivant ici https://blog.joeymasip.com/how-to-add-attributes-to-form-widgets-in-django-templates/

# utils.py
from django.template import Library
register = Library()

@register.filter(name='add_attr')
def add_attr(field, css):
    attrs = {}
    definition = css.split(',')

    for d in definition:
        if ':' not in d:
            attrs['class'] = d
        else:
            key, val = d.split(':')
            attrs[key] = val

    return field.as_widget(attrs=attrs)

utilisez la balise dans le fichier html

{% load utils %}
{{ form.field_1|add_attr:"class:my_class1 my_class2" }}
{{ form.field_2|add_attr:"class:my_class1 my_class2,autocomplete:off" }}
ohlr
la source
0

Apparence et rendu du formulaire finalJ'ai passé plusieurs jours à essayer de créer des modèles de formulaires réutilisables pour créer et mettre à jour des modèles dans les formulaires Django. Notez que j'utilise ModelForm pour modifier ou créer un objet. J'utilise aussi bootstrap pour styliser mes formulaires. J'ai utilisé django_form_tweaks pour certains formulaires dans le passé, mais j'avais besoin d'une certaine personnalisation sans beaucoup de dépendance de modèle. Comme j'ai déjà jQuery dans mon projet, j'ai décidé d'exploiter ses propriétés pour styliser mes formulaires. Voici le code, et peut fonctionner avec n'importe quel formulaire.

#forms.py
from django import forms
from user.models import User, UserProfile
from .models import Task, Transaction

class AddTransactionForm(forms.ModelForm):
    class Meta:
       model = Transaction
       exclude = ['ref_number',]
       required_css_class = 'required'

Views.py

@method_decorator(login_required, name='dispatch')
class TransactionView(View):
def get(self, *args, **kwargs):
    transactions = Transaction.objects.all()
    form = AddTransactionForm
    template = 'pages/transaction.html'
    context = {
        'active': 'transaction',
        'transactions': transactions,
        'form': form
    }
    return render(self.request, template, context)

def post(self, *args, **kwargs):
    form = AddTransactionForm(self.request.POST or None)
    if form.is_valid():
        form.save()
        messages.success(self.request, 'New Transaction recorded succesfully')
        return redirect('dashboard:transaction')
    messages.error(self.request, 'Fill the form')
    return redirect('dashboard:transaction')

Remarque sur le code HTML : J'utilise le modal bootstrap4 pour supprimer les tracas liés à la création de nombreuses vues. Il est peut-être préférable d'utiliser CreateView ou UpdateView générique. Lier Bootstrap et jqQery

 <div class="modal-body">
    <form method="post" class="md-form" action="." enctype="multipart/form-data">
      {% csrf_token %}
      {% for field in form %}
      <div class="row">
        <div class="col-md-12">
          <div class="form-group row">
            <label for="" class="col-sm-4 col-form-label {% if field.field.required %}
            required font-weight-bolder text-danger{%endif %}">{{field.label}}</label>
            <div class="col-sm-8">
              {{field}}
            </div>

          </div>
        </div>
      </div>

      {% endfor %}

      <input type="submit" value="Add Transaction" class="btn btn-primary">
    </form>
  </div>

Code Javascript n'oubliez pas de charger ceci en $(document).ready(function() { /* ... */});fonction.

var $list = $("#django_form :input[type='text']");
$list.each(function () {
    $(this).addClass('form-control')
  });
  var $select = $("#django_form select");
  $select.each(function () {
    $(this).addClass('custom-select w-90')
  });
  var $list = $("#django_form :input[type='number']");
  $list.each(function () {
    $(this).addClass('form-control')
  });
  var $list = $("form :input[type='text']");
  $list.each(function () {
    $(this).addClass('form-control')
  });
  var $select = $("form select");
  $select.each(function () {
    $(this).addClass('custom-select w-90')
  });
  var $list = $("form :input[type='number']");
  $list.each(function () {
    $(this).addClass('form-control')
  });
Fahrer Feyton
la source