Django: come aggiungo attributi HTML arbitrari ai campi di input in un modulo?


101

Ho un campo di input che viene visualizzato con un modello in questo modo:

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

Che è reso come:

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

Supponiamo ora di voler aggiungere un autocomplete="off"attributo all'elemento di input che viene visualizzato, come lo farei? O onclick="xyz()"o class="my-special-css-class"?

Risposte:


126

Controlla questa pagina

city = forms.CharField(widget=forms.TextInput(attrs={'autocomplete':'off'}))

2
Ok grazie. Nel mio caso sto usando ModelForm quindi non sto definendo esplicitamente i campi del modulo (ad esempio class AddressForm (forms.ModelForm): class Meta: model = models.Address) Questo significa che non posso usare ModelForm o c'è qualcosa di speciale che ho bisogno di fare?
Utente


1
@InfinitelyLoopy all'interno del form init for, puoi aggiungere del codice per afferrare il campo e modificare i suoi attributi dei widget. Eccone alcuni che ho usato in precedenza per modificare 3 campi: `` for field_name in ['image', 'image_small', 'image_mobile']: field = self.fields.get (field_name) field.widget.attrs ['data- file '] =' file '``
Stuart Axon

4
E gli attributi che non accettano argomenti come "obbligatorio" e "autofocus"?
Wilhelm Klopp

1
Questa soluzione è cattiva perché non c'è separazione delle preoccupazioni. Gli attributi HTML non devono essere scritti in codice Python IMO. La soluzione di Mikhail Korobov è superiore.
David D.

115

Ci scusiamo per la pubblicità, ma di recente ho rilasciato un'app ( https://github.com/kmike/django-widget-tweaks ) che rende tali attività ancora meno dolorose in modo che i progettisti possano farlo senza toccare il codice Python:

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

o, in alternativa,

{% load widget_tweaks %}
...
<div class="field">
   {% render_field form.city autocomplete="off" class+="my_css_class" %}
</div>

3
Bella app Mike, proprio quello che stavo cercando!
jmagnusson

la documentazione non ti dice di aggiungere "widget_tweaks" nella tua app installata nelle impostazioni, potrebbe valere la pena inserirlo nella documentazione.
James Lin

Ciao James, non è sottolineato ma nella sezione "Installazione" c'è già una nota sull'aggiunta di "widget_tweaks" a INSTALLED_APPS.
Mikhail Korobov

@MikhailKorobov grazie mille per questa app, mi ha aiutato molto! Questa era proprio la cosa giusta che stavo cercando. Avevo bisogno di un modulo da ModelForm e non volevo inserire manualmente questi attributi in ogni singolo campo (40 di essi), quindi sono riuscito elegantemente a ottenere lo stesso risultato in pochi secondi :) Questa dovrebbe essere la risposta accettata!
Ljubisa Livac

Avevo intenzione di scrivere tale applicazione. Grazie per aver salvato il mio impegno.
Anuj TBE

31

Se stai usando "ModelForm":

class YourModelForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(YourModelForm, self).__init__(*args, **kwargs)
        self.fields['city'].widget.attrs.update({
            'autocomplete': 'off'
        })

3
Buona! Non c'è bisogno di definire esplicitamente tutti i widget ora.
Mikael Lindlöf

20

Se stai usando ModelForm, a parte la possibilità di utilizzare __init__come @Artificioo fornito nella sua risposta, c'è un widgetsdizionario in Meta per quella materia:

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

Documentazione pertinente


1
Cercando di capire perché questo ha ottenuto meno voti positivi rispetto alla risposta sopra ... a volte penso che gli sviluppatori Django / Python preferiscano semplicemente il modo più difficile di fare le cose ...
trpt4him

@ trpt4him L'uso dell'approccio init è utile per creare un Mixin o una Classe Base che puoi riutilizzare in altri Form. Questo è tipico di un progetto su scala medio-grande. Meta.widgets è ottimo per un singolo modulo. Quindi, entrambe sono buone risposte.
Akhorus

2

Non volevo usare un'intera app per questa cosa. Invece ho trovato il seguente codice qui 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)

usa il tag nel file 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" }}

0

Aspetto e rendering della forma finaleHo passato diversi giorni a cercare di creare modelli di modulo riutilizzabili per creare e aggiornare modelli nei moduli Django. Nota che sto usando ModelForm per modificare o creare oggetti. Sto usando anche bootstrap per modellare i miei moduli. Ho usato django_form_tweaks per alcuni moduli in passato, ma avevo bisogno di personalizzazione senza molte dipendenze dai modelli. Dato che ho già jQuery nel mio progetto, ho deciso di sfruttare le sue proprietà per modellare i miei moduli. Ecco il codice e può funzionare con qualsiasi modulo.

#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')

Nota sul codice HTML : sto usando bootstrap4 modal per rimuovere il fastidio di creare molte visualizzazioni. Forse è meglio usare CreateView o UpdateView generici. Collega Bootstrap e 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>

Codice Javascript ricordati di caricarlo nella $(document).ready(function() { /* ... */});funzione.

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')
  });
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.