Django: Wie füge ich Eingabefeldern in einem Formular beliebige HTML-Attribute hinzu?

101

Ich habe ein Eingabefeld, das mit einer Vorlage wie folgt gerendert wird:

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

Welches wird gerendert als:

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

Angenommen, ich möchte dem autocomplete="off"gerenderten Eingabeelement ein Attribut hinzufügen. Wie würde ich das tun? Oder onclick="xyz()"oder class="my-special-css-class"?

Benutzer
quelle

Antworten:

126

Überprüfen Sie diese Seite

city = forms.CharField(widget=forms.TextInput(attrs={'autocomplete':'off'}))
Galen
quelle
2
OK danke. In meinem Fall verwende ich ModelForm, daher definiere ich die Formularfelder nicht explizit (z. B. Klasse AddressForm (forms.ModelForm): Klasse Meta: model = models.Address) Bedeutet dies, dass ich ModelForm nicht verwenden kann oder dass es etwas Besonderes gibt tun müssen?
Benutzer
1
@InfinitelyLoopy Innerhalb des Init for-Formulars können Sie Code hinzufügen, um das Feld zu erfassen und seine Widgets-Attribute zu ändern. Hier sind einige, die ich zuvor verwendet habe, um 3 Felder zu ändern: `` `für Feldname in ['Bild', 'Bild_small', 'Bild_Mobil']: field = self.fields.get (Feldname) field.widget.attrs ['data- file '] =' file '`` `
Stuart Axon
4
Was ist mit Attributen, die keine Argumente wie "erforderlich" und "Autofokus" enthalten?
Wilhelm Klopp
1
Diese Lösung ist schlecht, weil es keine Trennung von Bedenken gibt. HTML-Attribute sollten nicht in Python-Code IMO geschrieben werden. Mikhail Korobov Lösung ist überlegen.
David D.
114

Entschuldigung für die Werbung, aber ich habe kürzlich eine App veröffentlicht ( https://github.com/kmike/django-widget-tweaks ), die solche Aufgaben noch weniger schmerzhaft macht, sodass Designer dies tun können, ohne den Python-Code zu berühren:

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

oder alternativ,

{% load widget_tweaks %}
...
<div class="field">
   {% render_field form.city autocomplete="off" class+="my_css_class" %}
</div>
Mikhail Korobov
quelle
3
Schöne App Mike, genau das, wonach ich gesucht habe!
jmagnusson
In der Dokumentation wird nicht angegeben, dass Sie in den Einstellungen "widget_tweaks" zu Ihrer installierten App hinzufügen sollen. Möglicherweise lohnt es sich, dies in die Dokumentation aufzunehmen.
James Lin
Hallo James, es wird nicht betont, aber im Abschnitt 'Installation' gibt es bereits einen Hinweis zum Hinzufügen von 'widget_tweaks' zu INSTALLED_APPS.
Mikhail Korobov
@MikhailKorobov Vielen Dank für diese App, es hat mir sehr geholfen! Das war genau das Richtige, wonach ich gesucht habe. Ich brauchte ein Formular von ModelForm und wollte diese Attribute nicht manuell in jedes einzelne Feld einfügen (40 davon), also habe ich es elegant geschafft, in Sekunden das gleiche Ergebnis zu erzielen :) Dies sollte die akzeptierte Antwort sein!
Ljubisa Livac
Ich hatte vor, eine solche Bewerbung zu schreiben. Vielen Dank, dass ich meine Mühe gespart habe.
Anuj TBE
31

Wenn Sie "ModelForm" verwenden:

class YourModelForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(YourModelForm, self).__init__(*args, **kwargs)
        self.fields['city'].widget.attrs.update({
            'autocomplete': 'off'
        })
Artificioo
quelle
3
Gut! Sie müssen jetzt nicht alle Widgets explizit definieren.
Mikael Lindlöf
20

Wenn Sie verwenden, gibt es ModelForm, abgesehen von der Möglichkeit, __init__@Artificioo in seiner Antwort zu verwenden, ein widgetsWörterbuch in Meta für diese Angelegenheit:

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

Relevante Dokumentation

Wtower
quelle
1
Ich versuche herauszufinden, warum dies weniger positive Stimmen als die obige Antwort hat ... manchmal denke ich, dass Django / Python-Entwickler einfach die schwierigere Art bevorzugen, Dinge zu tun ...
trpt4him
@ trpt4him Die Verwendung des init- Ansatzes ist nützlich, um ein Mixin oder eine Basisklasse zu erstellen, die Sie in anderen Formularen wiederverwenden können. Dies ist typisch für ein mittelgroßes bis großes Projekt. Die Meta.widgets eignen sich hervorragend für ein einzelnes Formular. Beides sind also gute Antworten.
Akhorus
2

Ich wollte nicht eine ganze App für diese Sache verwenden. Stattdessen habe ich hier den folgenden Code gefunden: 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)

Verwenden Sie das Tag in der HTML-Datei

{% 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
quelle
0

Aussehen und Rendering des endgültigen FormularsIch habe einige Tage damit verbracht, wiederverwendbare Formularvorlagen zu erstellen, um Modelle in Django-Formularen zu erstellen und zu aktualisieren. Beachten Sie, dass Sie ModelForm zum Ändern oder Erstellen von Objekten verwenden. Ich benutze auch Bootstrap, um meine Formulare zu stylen. Ich habe in der Vergangenheit für einige Formulare django_form_tweaks verwendet, aber ich musste einige Anpassungen ohne große Vorlagenabhängigkeit vornehmen. Da ich jQuery bereits in meinem Projekt habe, habe ich beschlossen, seine Eigenschaften zu nutzen, um meine Formulare zu gestalten. Hier ist der Code und kann mit jeder Form arbeiten.

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

HTML-Code Hinweis: Ich verwende Bootstrap4 Modal, um den Aufwand beim Erstellen vieler Ansichten zu beseitigen. Vielleicht ist es besser, generisches CreateView oder UpdateView zu verwenden. Verknüpfen Sie Bootstrap und 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>

Javascript Code Denken Sie daran, dies in $(document).ready(function() { /* ... */});Funktion zu laden .

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
quelle