Django: Jak dodać dowolne atrybuty html do pól wejściowych w formularzu?

102

Mam pole wejściowe, które jest renderowane za pomocą szablonu takiego:

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

Który jest renderowany jako:

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

Teraz przypuśćmy, że chcę dodać autocomplete="off"atrybut do renderowanego elementu wejściowego, jak mam to zrobić? Albo onclick="xyz()"albo class="my-special-css-class"?

Użytkownik
źródło

Odpowiedzi:

126

Sprawdź tę stronę

city = forms.CharField(widget=forms.TextInput(attrs={'autocomplete':'off'}))
Galen
źródło
2
Ok dziękuję. W moim przypadku używam ModelForm, więc nie definiuję jawnie pól formularza (np. Klasa AddressForm (forms.ModelForm): class Meta: model = models.Address) Czy to oznacza, że ​​nie mogę używać ModelForm lub czy jest coś specjalnego? musieć zrobić?
Użytkownik
1
ok, nieważne, rtfm: docs.djangoproject.com/en/dev/topics/forms/modelforms
Użytkownik
1
@InfinitelyLoopy wewnątrz init for form, możesz dodać kod, aby pobrać pole i zmodyfikować jego atrybuty widżetów. Oto niektóre, których użyłem wcześniej do zmodyfikowania 3 pól: `` for field_name in ['image', 'image_small', 'image_mobile']: field = self.fields.get (field_name) field.widget.attrs ['data- file '] =' file '``
Stuart Axon
4
A co z atrybutami, które nie przyjmują argumentów, takich jak „wymagany” i „autofokus”?
Wilhelm Klopp
1
To rozwiązanie jest złe, ponieważ nie ma rozdzielenia obaw. Atrybuty HTML nie powinny być zapisywane w kodzie IMO w języku Python. Rozwiązanie Michaiła Korobowa jest lepsze.
David D.
116

Przepraszam za reklamę, ale niedawno wydałem aplikację ( https://github.com/kmike/django-widget-tweaks ), która sprawia, że ​​takie zadania są jeszcze mniej bolesne, więc projektanci mogą to robić bez dotykania kodu Pythona:

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

lub alternatywnie

{% load widget_tweaks %}
...
<div class="field">
   {% render_field form.city autocomplete="off" class+="my_css_class" %}
</div>
Michaił Korobow
źródło
3
Niezła aplikacja Mike, właśnie tego szukałem!
jmagnusson
dokumentacja nie mówi o dodaniu „widget_tweaks” do zainstalowanej aplikacji w ustawieniach, warto umieścić to w dokumentacji.
James Lin
Cześć James, nie jest to podkreślone, ale w sekcji „Instalacja” jest już notatka o dodaniu „widget_tweaks” do INSTALLED_APPS.
Michaił Korobow
@MikhailKorobov bardzo dziękuję za tę aplikację, bardzo mi pomogła! To była właściwa rzecz, której szukałem. Potrzebowałem formularza z ModelForm i nie chciałem ręcznie wstawiać tych atrybutów do każdego pola (40 z nich), więc elegancko udało mi się osiągnąć ten sam wynik w kilka sekund :) To powinna być zaakceptowana odpowiedź!
Ljubisa Livac
Planowałem napisać taką aplikację. Dzięki oszczędzeniu mojego wysiłku.
Anuj TBE
32

Jeśli używasz „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
źródło
3
Dobry! Nie ma teraz potrzeby jawnego definiowania wszystkich widżetów.
Mikael Lindlöf
21

Jeśli korzystasz ModelForm, oprócz możliwości użycia __init__jako @Artificioo podanego w jego odpowiedzi, widgetsw Meta jest do tego słownik:

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

Odpowiednia dokumentacja

Wtower
źródło
1
Próbuję dowiedzieć się, dlaczego otrzymałem mniej głosów pozytywnych niż odpowiedź powyżej ... czasami myślę, że programiści Django / Python po prostu wolą trudniejszy sposób robienia rzeczy ...
trpt4him
@ trpt4him Użycie podejścia init jest przydatne do tworzenia klasy Mixin lub Base, których można ponownie używać w innych formularzach. Jest to typowe w przypadku projektów o średniej i dużej skali. Meta.widgets świetnie nadaje się do pojedynczego formularza. Tak więc obie odpowiedzi są dobre.
Akhorus
3

Nie chciałem używać do tego całej aplikacji. Zamiast tego znalazłem następujący kod tutaj 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)

użyj tagu w pliku 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
źródło
0

Ostateczny wygląd i renderowanie formySpędziłem kilka dni próbując stworzyć szablony formularzy wielokrotnego użytku do tworzenia i aktualizowania modeli w formularzach Django. Zauważ, że używam ModelForm do zmiany lub tworzenia obiektu. Używam również bootstrapu do stylizacji moich formularzy. W przeszłości używałem django_form_tweaks do niektórych formularzy, ale potrzebowałem dostosowania bez dużej zależności od szablonu. Ponieważ mam już jQuery w moim projekcie, zdecydowałem się wykorzystać jego właściwości do stylizacji moich formularzy. Oto kod i może pracować z dowolnym formularzem.

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

Uwaga dotycząca kodu HTML : Używam modalu bootstrap4, aby uniknąć kłopotów związanych z tworzeniem wielu widoków. Może lepiej jest użyć ogólnego CreateView lub UpdateView. Połącz Bootstrap i 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>

Kod JavaScript pamiętaj, aby załadować to w $(document).ready(function() { /* ... */});funkcji.

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
źródło