Django: banyak model dalam satu templat menggunakan formulir [tertutup]

114

Saya sedang membangun aplikasi pelacakan tiket dukungan dan memiliki beberapa model yang ingin saya buat dari satu halaman. Tiket menjadi milik Pelanggan melalui ForeignKey. Catatan juga termasuk dalam Tiket melalui ForeignKey. Saya ingin memiliki opsi untuk memilih Pelanggan (itu adalah proyek yang terpisah) ATAU membuat Pelanggan baru, lalu membuat Tiket dan akhirnya membuat Catatan yang ditetapkan ke tiket baru.

Karena saya cukup baru di Django, saya cenderung bekerja secara berulang, mencoba fitur baru setiap kali. Saya telah bermain dengan ModelForms tetapi saya ingin menyembunyikan beberapa bidang dan melakukan beberapa validasi yang kompleks. Sepertinya tingkat kontrol yang saya cari membutuhkan kumpulan formulir atau melakukan semuanya dengan tangan, lengkap dengan halaman templat kode tangan yang membosankan, yang saya coba hindari.

Apakah ada beberapa fitur menarik yang saya lewatkan? Apakah seseorang memiliki referensi atau contoh yang baik untuk menggunakan kumpulan formulir? Saya menghabiskan seluruh akhir pekan di dokumen API untuk mereka dan saya masih tidak mengerti. Apakah ini masalah desain jika saya rusak dan membuat kode manual semuanya?

neoice
sumber
pada awalnya Anda harus memvalidasi formulir pelanggan Anda dan jika itu valid, buat salinan dari request.POST (new_data = request.POST.copy ()). dan kemudian dapatkan id pelanggan (dari formulir pelanggan yang divalidasi) dan dengan memperbarui new_data, buat id pelanggan nilai ke bidang kunci asing (mungkin pelanggan dalam model Anda). Dan terakhir pertimbangkan data_baru untuk memvalidasi formulir kedua Anda (Tiket)
Negar37

Jawaban:

87

Ini sebenarnya tidak terlalu sulit untuk diterapkan dengan ModelForms . Jadi katakanlah Anda memiliki Formulir A, B, dan C. Anda mencetak setiap formulir dan halaman dan sekarang Anda perlu menangani POST.

if request.POST():
    a_valid = formA.is_valid()
    b_valid = formB.is_valid()
    c_valid = formC.is_valid()
    # we do this since 'and' short circuits and we want to check to whole page for form errors
    if a_valid and b_valid and c_valid:
        a = formA.save()
        b = formB.save(commit=False)
        c = formC.save(commit=False)
        b.foreignkeytoA = a
        b.save()
        c.foreignkeytoB = b
        c.save()

Berikut adalah dokumen untuk validasi kustom.

Jason Christa
sumber
2
Ngomong-ngomong, menurut saya kumpulan formulir bukanlah solusi yang baik untuk masalah yang Anda jelaskan. Saya selalu menggunakannya untuk mewakili banyak contoh model. Misalnya Anda memiliki formulir pelamar dan Anda ingin 3 referensi untuk Anda membuat formulir yang memiliki 3 contoh model Referensi.
Jason Christa
1
perhatikan bahwa, dengan cara Anda melakukannya, panggilan .is_valid () tidak dihubung pendek. Jika Anda ingin melakukan short circuit, Anda harus menunda pemanggilan fungsi .is_valid () hingga 'dan'.
Lie Ryan
66

Saya baru saja mengalami situasi yang sama sehari yang lalu, dan ini 2 sen saya:

1) Saya menemukan demonstrasi terpendek dan paling ringkas dari beberapa entri model dalam bentuk tunggal di sini: http://collingrady.wordpress.com/2008/02/18/editing-multiple-objects-in-django-with-newforms/ .

Singkatnya: Buat formulir untuk setiap model, kirimkan keduanya ke template dalam satu <form>, menggunakan prefixkeyarg dan minta validasi pegangan tampilan. Jika ada ketergantungan, pastikan Anda menyimpan model "induk" sebelum bergantung, dan gunakan ID induk untuk kunci asing sebelum melakukan penyimpanan model "anak". Tautan memiliki demo.

2) Mungkin formsets dapat dipukuli dalam melakukan hal ini, tapi sejauh yang saya menggali di, formsets terutama untuk memasuki kelipatan dari model yang sama, yang mungkin secara opsional diikat ke model lain / model dengan kunci asing. Namun, tampaknya tidak ada opsi default untuk memasukkan lebih dari satu data model dan sepertinya bukan itu yang dimaksudkan untuk formset.

Gnudiff
sumber
26

Saya baru-baru ini mengalami masalah dan baru saja menemukan cara untuk melakukan ini. Dengan asumsi Anda memiliki tiga kelas, Primer, B, C dan B, C memiliki kunci asing ke primer

    class PrimaryForm(ModelForm):
        class Meta:
            model = Primary

    class BForm(ModelForm):
        class Meta:
            model = B
            exclude = ('primary',)

    class CForm(ModelForm):
         class Meta:
            model = C
            exclude = ('primary',)

    def generateView(request):
        if request.method == 'POST': # If the form has been submitted...
            primary_form = PrimaryForm(request.POST, prefix = "primary")
            b_form = BForm(request.POST, prefix = "b")
            c_form = CForm(request.POST, prefix = "c")
            if primary_form.is_valid() and b_form.is_valid() and c_form.is_valid(): # All validation rules pass
                    print "all validation passed"
                    primary = primary_form.save()
                    b_form.cleaned_data["primary"] = primary
                    b = b_form.save()
                    c_form.cleaned_data["primary"] = primary
                    c = c_form.save()
                    return HttpResponseRedirect("/viewer/%s/" % (primary.name))
            else:
                    print "failed"

        else:
            primary_form = PrimaryForm(prefix = "primary")
            b_form = BForm(prefix = "b")
            c_form = Form(prefix = "c")
     return render_to_response('multi_model.html', {
     'primary_form': primary_form,
     'b_form': b_form,
     'c_form': c_form,
      })

Metode ini memungkinkan Anda melakukan validasi apa pun yang Anda perlukan, serta menghasilkan ketiga objek di halaman yang sama. Saya juga menggunakan javascript dan bidang tersembunyi untuk memungkinkan pembuatan beberapa objek B, C pada halaman yang sama.


sumber
3
Dalam contoh ini, bagaimana Anda menyetel kunci asing untuk model B dan C agar mengarah ke model Primer?
Pengguna
Saya hanya punya dua model yang ingin saya tunjukkan dalam bentuk yang sama. Tapi saya tidak mendapatkan pernyataan exclude = ('primary',). Apa yang utama? Jika memiliki 2 model CustomerConfig dan Contract. Kontrak memiliki kunci asing untuk CustomerConfig. Seperti customer_config = models.ForeignKey ('CustomerPartnerConfiguration') Apa itu 'primer'?
pitchblack408
10

The MultiModelForm dari django-betterformsadalah pembungkus nyaman untuk melakukan apa yang dijelaskan dalam jawaban Gnudiff ini . Ini membungkus reguler ModelFormdalam satu kelas yang secara transparan (setidaknya untuk penggunaan dasar) digunakan sebagai satu bentuk. Saya telah menyalin contoh dari dokumen mereka di bawah ini.

# forms.py
from django import forms
from django.contrib.auth import get_user_model
from betterforms.multiform import MultiModelForm
from .models import UserProfile

User = get_user_model()

class UserEditForm(forms.ModelForm):
    class Meta:
        fields = ('email',)

class UserProfileForm(forms.ModelForm):
    class Meta:
        fields = ('favorite_color',)

class UserEditMultiForm(MultiModelForm):
    form_classes = {
        'user': UserEditForm,
        'profile': UserProfileForm,
    }

# views.py
from django.views.generic import UpdateView
from django.core.urlresolvers import reverse_lazy
from django.shortcuts import redirect
from django.contrib.auth import get_user_model
from .forms import UserEditMultiForm

User = get_user_model()

class UserSignupView(UpdateView):
    model = User
    form_class = UserEditMultiForm
    success_url = reverse_lazy('home')

    def get_form_kwargs(self):
        kwargs = super(UserSignupView, self).get_form_kwargs()
        kwargs.update(instance={
            'user': self.object,
            'profile': self.object.profile,
        })
        return kwargs
jozxyqk.dll
sumber
Lihat saja django-betterformsdan kelas MultiModelFormnya sebelum menemukan jawaban Anda. Solusi mereka terlihat sangat bagus tetapi tampaknya belum diperbarui untuk sementara waktu. Apakah Anda masih menggunakan @jozxyqk ini? Masalah apapun?
enchance
@enchance sudah beberapa tahun. Saat itu saya merasa nyaman dan salah satu opsi yang lebih baik. Jika Anda tidak terlalu menyukainya, ini akan menghemat waktu. Saya bisa membayangkan ketika Anda ingin mulai menyesuaikan dan melakukan bentuk non-sepele, akan lebih mudah untuk menggulung sendiri. Memadukan bentuk dan konteks dengan mudah dalam tampilan adalah fitur pertama yang menurut saya terlewat di django.
jozxyqk
Terima kasih atas jawabannya. Saya mempertimbangkan untuk hanya mem-forkingnya dan mungkin memperbarui beberapa hal di sepanjang jalan. Dari apa yang saya lihat sejauh ini, itu berfungsi dengan baik. Anda benar, ini sangat menghemat waktu.
enchance
5

Saat ini saya memiliki fungsionalitas solusi (lulus tes unit saya). Ini adalah solusi yang bagus untuk pendapat saya ketika Anda hanya ingin menambahkan sejumlah bidang dari model lain.

Apakah saya melewatkan sesuatu di sini?

class UserProfileForm(ModelForm):
    def __init__(self, instance=None, *args, **kwargs):
        # Add these fields from the user object
        _fields = ('first_name', 'last_name', 'email',)
        # Retrieve initial (current) data from the user object
        _initial = model_to_dict(instance.user, _fields) if instance is not None else {}
        # Pass the initial data to the base
        super(UserProfileForm, self).__init__(initial=_initial, instance=instance, *args, **kwargs)
        # Retrieve the fields from the user model and update the fields with it
        self.fields.update(fields_for_model(User, _fields))

    class Meta:
        model = UserProfile
        exclude = ('user',)

    def save(self, *args, **kwargs):
        u = self.instance.user
        u.first_name = self.cleaned_data['first_name']
        u.last_name = self.cleaned_data['last_name']
        u.email = self.cleaned_data['email']
        u.save()
        profile = super(UserProfileForm, self).save(*args,**kwargs)
        return profile
Paul Bormans
sumber
3

"Saya ingin menyembunyikan beberapa bidang dan melakukan validasi yang rumit."

Saya mulai dengan antarmuka admin bawaan.

  1. Buat ModelForm untuk menampilkan bidang yang diinginkan.

  2. Perluas Formulir dengan aturan validasi di dalam formulir. Biasanya ini adalahclean metode.

    Pastikan bagian ini berfungsi dengan baik.

Setelah ini selesai, Anda dapat keluar dari antarmuka admin bawaan.

Kemudian Anda dapat bermain-main dengan beberapa formulir yang sebagian terkait pada satu halaman web. Ini adalah sekumpulan barang template untuk menampilkan semua formulir dalam satu halaman.

Kemudian Anda harus menulis fungsi view untuk membaca dan memvalidasi berbagai form dan melakukan berbagai object saves ().

"Apakah ini masalah desain jika saya rusak dan membuat kode manual semuanya?" Tidak, ini hanya waktu yang lama dan tidak banyak manfaatnya.

S. Lott
sumber
Saya tidak tahu caranya, oleh karena itu jangan lakukan
orokusaki
1
@orokusaki: Apa lagi yang Anda suka? Itu sepertinya menggambarkan sebuah solusi. Apa lagi yang harus dikatakan? Pertanyaannya tidak jelas, jadi sulit untuk memberikan kode sebenarnya. Daripada mengeluh, tolong berikan saran untuk perbaikan. Apa yang Anda sarankan?
S. Lott