Django: Bagaimana cara menambahkan atribut html sembarangan ke bidang masukan pada formulir?

101

Saya memiliki kolom input yang dirender dengan template seperti ini:

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

Yang diterjemahkan sebagai:

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

Sekarang misalkan saya ingin menambahkan autocomplete="off"atribut ke elemen masukan yang diberikan, bagaimana saya melakukannya? Atau onclick="xyz()"atau class="my-special-css-class"?

Pengguna
sumber

Jawaban:

126

Periksa halaman ini

city = forms.CharField(widget=forms.TextInput(attrs={'autocomplete':'off'}))
Galen
sumber
2
Oke terima kasih. Dalam kasus saya, saya menggunakan ModelForm jadi saya tidak secara eksplisit mendefinisikan bidang formulir (misalnya kelas AddressForm (forms.ModelForm): class Meta: model = models.Address) Apakah ini berarti saya tidak dapat menggunakan ModelForm atau adakah sesuatu yang istimewa saya perlu dilakukan?
Pengguna
1
ok tidak masalah, rtfm: docs.djangoproject.com/en/dev/topics/forms/modelforms
Pengguna
1
@InfinitelyLoopy di dalam init for form, Anda dapat menambahkan beberapa kode untuk mengambil bidang dan mengubah atribut widgetnya. Berikut adalah beberapa yang saya gunakan sebelumnya untuk memodifikasi 3 bidang: `` untuk nama_field di ['image', 'image_small', 'image_mobile']: field = self.fields.get (field_name) field.widget.attrs ['data- file '] =' file '``
Stuart Axon
4
Bagaimana dengan atribut yang tidak mengambil argumen seperti 'diperlukan' dan 'fokus otomatis'?
Wilhelm Klopp
1
Solusi ini buruk karena tidak ada pemisahan kekhawatiran. Atribut HTML tidak boleh ditulis dalam kode python IMO. Solusi Mikhail Korobov lebih unggul.
David D.
115

Maaf untuk iklannya, tetapi saya baru-baru ini merilis sebuah aplikasi ( https://github.com/kmike/django-widget-tweaks ) yang membuat tugas-tugas seperti itu semakin tidak menyakitkan sehingga desainer dapat melakukannya tanpa menyentuh kode python:

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

atau, sebagai alternatif,

{% load widget_tweaks %}
...
<div class="field">
   {% render_field form.city autocomplete="off" class+="my_css_class" %}
</div>
Mikhail Korobov
sumber
3
Aplikasi bagus Mike, persis apa yang saya cari!
jmagnusson
dokumentasi tidak memberitahu Anda untuk menambahkan "widget_tweaks" ke dalam aplikasi yang Anda instal di pengaturan, mungkin layak untuk dimasukkan ke dalam dokumentasi.
James Lin
Hai James, ini tidak stres tetapi di bagian 'Instalasi' sudah ada catatan tentang menambahkan 'widget_tweaks' ke INSTALLED_APPS.
Mikhail Korobov
@MikhailKorobov terima kasih banyak untuk aplikasi ini, itu sangat membantu saya! Ini adalah hal benar yang saya cari. Saya membutuhkan formulir dari ModelForm dan tidak ingin memasukkan atribut ini secara manual ke setiap bidang (40 di antaranya), jadi saya dengan elegan berhasil mencapai hasil yang sama dalam hitungan detik :) Ini harus menjadi jawaban yang diterima!
Ljubisa Livac
Saya berencana untuk menulis aplikasi seperti itu. Terima kasih telah menyelamatkan usaha saya.
Anuj TBE
31

Jika Anda menggunakan "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
sumber
3
Baik! Tidak perlu mendefinisikan semua widget secara eksplisit sekarang.
Mikael Lindlöf
20

Jika Anda menggunakan ModelForm, selain kemungkinan menggunakan __init__@Artificioo yang diberikan dalam jawabannya, ada widgetskamus di Meta untuk hal itu:

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

Dokumentasi yang relevan

Wtower
sumber
1
Mencoba untuk mencari tahu mengapa ini mendapat lebih sedikit suara positif daripada jawaban di atas ... terkadang saya pikir pengembang Django / Python lebih suka cara yang lebih sulit dalam melakukan sesuatu ...
trpt4him
@ trpt4him Menggunakan pendekatan init berguna untuk membuat Mixin atau Kelas Dasar yang dapat Anda gunakan kembali di Formulir lain. Ini adalah tipikal dalam proyek skala menengah hingga besar. Meta.widgets sangat bagus untuk satu Formulir. Jadi, keduanya adalah jawaban yang bagus.
Akhorus
3

Saya tidak ingin menggunakan seluruh aplikasi untuk hal ini. Sebaliknya saya menemukan kode berikut di sini 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)

gunakan tag di 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" }}
ohlr
sumber
0

Tampilan dan rendering bentuk akhirSaya telah menghabiskan beberapa hari mencoba membuat templat formulir yang dapat digunakan kembali untuk membuat dan memperbarui model dalam formulir Django. Perhatikan bahwa saya menggunakan ModelForm untuk mengubah atau membuat objek. Saya juga menggunakan bootstrap untuk menata formulir saya. Saya menggunakan django_form_tweaks untuk beberapa formulir di masa lalu, tetapi saya membutuhkan beberapa penyesuaian tanpa banyak ketergantungan template. Karena saya sudah memiliki jQuery di Proyek saya, saya memutuskan untuk memanfaatkan propertinya untuk menata formulir saya. Ini kodenya, dan dapat bekerja dengan bentuk apa pun.

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

Kode HTML Catatan: Saya menggunakan modal bootstrap4 untuk menghilangkan kerumitan membuat banyak tampilan. Mungkin lebih baik menggunakan CreateView atau UpdateView generik. Hubungkan Bootstrap dan 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>

Kode Javascript ingat untuk memuat ini dalam $(document).ready(function() { /* ... */});fungsi.

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
sumber