Katakanlah saya memiliki yang berikut ini di models.py
:
class Company(models.Model):
name = ...
class Rate(models.Model):
company = models.ForeignKey(Company)
name = ...
class Client(models.Model):
name = ...
company = models.ForeignKey(Company)
base_rate = models.ForeignKey(Rate)
Yaitu ada beberapa Companies
, masing-masing memiliki kisaran Rates
dan Clients
. Masing Client
- masing harus memiliki basis Rate
yang dipilih dari orang tuanya Company's Rates
, bukan yang lain Company's Rates
.
Saat membuat formulir untuk menambahkan Client
, saya ingin menghapus Company
pilihan (seperti yang telah dipilih melalui tombol "Tambah Klien" pada Company
halaman) dan batasi Rate
pilihan itu Company
juga.
Bagaimana saya melakukannya tentang Django 1.0?
forms.py
File saya saat ini hanyalah boilerplate saat ini:
from models import *
from django.forms import ModelForm
class ClientForm(ModelForm):
class Meta:
model = Client
Dan views.py
itu juga dasar:
from django.shortcuts import render_to_response, get_object_or_404
from models import *
from forms import *
def addclient(request, company_id):
the_company = get_object_or_404(Company, id=company_id)
if request.POST:
form = ClientForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(the_company.get_clients_url())
else:
form = ClientForm()
return render_to_response('addclient.html', {'form': form, 'the_company':the_company})
Di Django 0.96 saya bisa meretas ini dengan melakukan sesuatu seperti berikut sebelum merender template:
manipulator.fields[0].choices = [(r.id,r.name) for r in Rate.objects.filter(company_id=the_company.id)]
ForeignKey.limit_choices_to
tampaknya menjanjikan tetapi saya tidak tahu bagaimana cara masuk the_company.id
dan saya tidak jelas apakah itu akan bekerja di luar antarmuka Admin.
Terima kasih. (Ini sepertinya permintaan yang cukup mendasar tetapi jika saya harus mendesain ulang sesuatu, saya terbuka untuk saran.)
Jawaban:
ForeignKey diwakili oleh django.forms.ModelChoiceField, yang merupakan ChoiceField yang pilihannya adalah model QuerySet. Lihat referensi untuk ModelChoiceField .
Jadi, berikan QuerySet ke
queryset
atribut bidang . Tergantung pada bagaimana formulir Anda dibangun. Jika Anda membuat formulir eksplisit, Anda akan memiliki bidang yang dinamai secara langsung.Jika Anda mengambil objek ModelForm default,
form.fields["rate"].queryset = ...
Ini dilakukan secara eksplisit dalam tampilan. Tidak perlu meretas.
sumber
__init__
?Selain jawaban S.Lott dan sebagaimana menjadiGuru disebutkan dalam komentar, dimungkinkan untuk menambahkan filter queryset dengan mengabaikan
ModelForm.__init__
fungsi. (Ini bisa dengan mudah diterapkan pada formulir biasa) ini dapat membantu menggunakan kembali dan menjaga fungsi tampilan tetap rapi.Ini dapat berguna untuk digunakan kembali katakan jika Anda memiliki filter umum yang diperlukan pada banyak model (biasanya saya mendeklarasikan kelas Formulir abstrak). Misalnya
Selain itu saya hanya ulangan materi blog Django yang ada banyak yang bagus di luar sana.
sumber
Ini sederhana, dan bekerja dengan Django 1.4:
Anda tidak perlu menentukan ini dalam kelas formulir, tetapi bisa melakukannya langsung di ModelAdmin, karena Django sudah menyertakan metode bawaan ini pada ModelAdmin (dari dokumen):
Cara yang bahkan lebih mudah untuk melakukan ini (misalnya dalam membuat antarmuka admin front-end yang dapat diakses pengguna) adalah dengan subkelas ModelAdmin dan kemudian ubah metode di bawah ini. Hasil bersihnya adalah antarmuka pengguna yang HANYA menunjukkan kepada mereka konten yang terkait dengannya, sambil memungkinkan Anda (pengguna super) melihat semuanya.
Saya telah mengganti empat metode, dua yang pertama tidak memungkinkan bagi pengguna untuk menghapus apa pun, dan itu juga menghapus tombol hapus dari situs admin.
Timpa ketiga memfilter kueri yang berisi referensi ke (dalam contoh 'pengguna' atau 'landak' (seperti ilustrasi).
Timpa terakhir memfilter bidang asing apa pun dalam model untuk memfilter pilihan yang tersedia sama dengan kueryset dasar.
Dengan cara ini, Anda dapat menyajikan situs admin yang menghadap ke depan yang mudah dikelola yang memungkinkan pengguna untuk mengacaukan objek mereka sendiri, dan Anda tidak harus ingat untuk mengetikkan filter ModelAdmin spesifik yang telah kita bicarakan di atas.
hapus tombol 'hapus':
mencegah izin hapus
memfilter objek yang dapat dilihat di situs admin:
memfilter pilihan untuk semua bidang asing di situs admin:
sumber
Untuk melakukan ini dengan tampilan umum, seperti CreateView ...
bagian terpenting dari itu ...
, baca posting saya di sini
sumber
Jika Anda belum membuat formulir dan ingin mengubah kueryset yang dapat Anda lakukan:
Ini sangat berguna saat Anda menggunakan tampilan umum!
sumber
Jadi, saya sudah benar-benar mencoba memahami ini, tetapi tampaknya Django masih tidak membuat ini dengan mudah. Aku tidak sebodoh itu, tapi aku tidak bisa melihat (agak) solusi sederhana.
Saya merasa secara umum sangat buruk untuk menimpa tampilan Admin untuk hal semacam ini, dan setiap contoh yang saya temukan tidak pernah sepenuhnya berlaku untuk tampilan Admin.
Ini adalah keadaan umum dengan model yang saya buat sehingga saya merasa mengerikan bahwa tidak ada solusi yang jelas untuk ini ...
Saya memiliki kelas-kelas ini:
Ini menimbulkan masalah ketika menyiapkan Admin untuk Perusahaan, karena memiliki inline untuk Kontrak dan Lokasi, dan opsi m2m Kontrak untuk Lokasi tidak difilter dengan benar menurut Perusahaan yang sedang Anda edit.
Singkatnya, saya perlu beberapa opsi admin untuk melakukan sesuatu seperti ini:
Pada akhirnya saya tidak akan peduli jika proses penyaringan ditempatkan pada basis CompanyAdmin, atau jika ditempatkan pada ContractInline. (Menempatkannya di garis lebih masuk akal, tetapi membuatnya sulit untuk merujuk Kontrak dasar sebagai 'diri'.)
Adakah orang di luar sana yang mengetahui sesuatu yang langsung seperti jalan pintas yang sangat dibutuhkan ini? Kembali ketika saya membuat admin PHP untuk hal semacam ini, ini dianggap fungsi dasar! Bahkan, itu selalu otomatis, dan harus dinonaktifkan jika Anda benar-benar tidak menginginkannya!
sumber
Cara yang lebih umum adalah dengan memanggil get_form di kelas Admin. Ini juga berfungsi untuk bidang non-database juga. Sebagai contoh di sini saya memiliki bidang yang disebut '_terminal_list' pada formulir yang dapat digunakan dalam kasus-kasus khusus untuk memilih beberapa item terminal dari get_list (permintaan), kemudian penyaringan berdasarkan pada request.user:
sumber