Powiedz, że mam w sobie następujące 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)
Tzn. Jest ich wiele Companies
, z których każdy ma zakres Rates
i Clients
. Każdy Client
powinien mieć bazę Rate
wybraną spośród jego rodzica Company's Rates
, a nie inną Company's Rates
.
Tworząc formularz dodawania a Client
, chciałbym usunąć Company
opcje (ponieważ zostały one już wybrane za pomocą przycisku „Dodaj klienta” na Company
stronie) i ograniczyć również te Rate
opcje Company
.
Jak to zrobić w Django 1.0?
Mój aktualny forms.py
plik jest w tej chwili tylko szablonem:
from models import *
from django.forms import ModelForm
class ClientForm(ModelForm):
class Meta:
model = Client
I to views.py
jest również podstawowe:
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})
W Django 0.96 byłem w stanie włamać się do tego, wykonując coś takiego przed renderowaniem szablonu:
manipulator.fields[0].choices = [(r.id,r.name) for r in Rate.objects.filter(company_id=the_company.id)]
ForeignKey.limit_choices_to
wydaje się obiecujące, ale nie wiem, jak się poddać the_company.id
i nie jestem i tak zadziała poza interfejsem administratora.
Dzięki. (To wydaje się być dość prostą prośbą, ale jeśli powinienem przeprojektować coś, jestem otwarty na sugestie).
źródło
Odpowiedzi:
ForeignKey jest reprezentowany przez django.forms.ModelChoiceField, czyli ChoiceField, którego wybory to model QuerySet. Zobacz odniesienie do ModelChoiceField .
Zatem podaj
queryset
atrybut QuerySet dla atrybutu pola . Zależy od sposobu zbudowania formularza. Jeśli zbudujesz jawny formularz, będziesz mieć pola nazwane bezpośrednio.Jeśli weźmiesz domyślny obiekt ModelForm,
form.fields["rate"].queryset = ...
Odbywa się to wyraźnie w widoku. Żadnego hakowania.
źródło
__init__
metodzie formularza ?Oprócz odpowiedzi S.Lott i gdy staje sięGuru wspomnianym w komentarzach, możliwe jest dodanie filtrów zestawu zapytań przez przesłonięcie
ModelForm.__init__
funkcji. (Może to łatwo dotyczyć zwykłych formularzy), może pomóc w ponownym użyciu i utrzymuje porządek w funkcji widoku.Może to być przydatne do ponownego użycia, powiedzmy, jeśli potrzebujesz wspólnych filtrów w wielu modelach (zwykle deklaruję abstrakcyjną klasę Form). Na przykład
Poza tym po prostu powtarzam materiały na blogu Django, z których jest wiele dobrych.
źródło
Jest to proste i działa z Django 1.4:
Nie musisz tego określać w klasie formularza, ale możesz to zrobić bezpośrednio w ModelAdmin, ponieważ Django już zawiera tę wbudowaną metodę w ModelAdmin (z dokumentacji):
Jeszcze szybszym sposobem na to (na przykład w tworzeniu interfejsu administracyjnego frontonu, do którego użytkownicy mogą uzyskać dostęp) jest podklasa ModelAdmin, a następnie zmiana poniższych metod. Rezultatem netto jest interfejs użytkownika, który TYLKO pokazuje im powiązaną z nimi treść, jednocześnie pozwalając Tobie (superużytkownikowi) zobaczyć wszystko.
Zastąpiłem cztery metody, dwie pierwsze uniemożliwiają użytkownikowi usunięcie czegokolwiek, a także usuwa przyciski usuwania z witryny administratora.
Trzecie przesłonięcie filtruje każde zapytanie zawierające odwołanie do (w przykładzie „użytkownik” lub „jeżozwierz” (tylko jako ilustracja).
Ostatnie przesłonięcie filtruje dowolne pole klucza obcego w modelu, aby filtrować dostępne opcje tak samo, jak podstawowy zestaw zapytań.
W ten sposób możesz zaprezentować łatwą w zarządzaniu frontową stronę administracyjną, która pozwala użytkownikom na bałagan z własnymi obiektami i nie musisz pamiętać o wpisywaniu określonych filtrów ModelAdmin, o których mówiliśmy powyżej.
usuń przyciski „usuń”:
uniemożliwia usunięcie uprawnienia
filtruje obiekty, które można oglądać na stronie administratora:
filtruje opcje dla wszystkich pól kluczy obcych w witrynie administratora:
źródło
Aby to zrobić za pomocą widoku ogólnego, takiego jak CreateView ...
najważniejsza część tego ...
, przeczytaj mój post tutaj
źródło
Jeśli nie utworzyłeś formularza i chcesz zmienić zestaw zapytań, możesz:
Jest to bardzo przydatne, gdy używasz widoków ogólnych!
źródło
Naprawdę próbowałem to zrozumieć, ale wygląda na to, że Django wciąż nie czyni tego bardzo prostym. Nie jestem aż tak głupi, ale po prostu nie widzę żadnego (nieco) prostego rozwiązania.
Uważam, że generalnie dość brzydka jest konieczność przesłonięcia widoków administratora dla tego rodzaju rzeczy, a każdy przykład, który uważam, nigdy nie dotyczy w pełni widoków administratora.
Jest to tak powszechna okoliczność w przypadku modeli, które sprawiają, że przerażam to, że nie ma oczywistego rozwiązania tego ...
Mam te zajęcia:
Stwarza to problem podczas konfigurowania Administratora dla firmy, ponieważ ma on wstawki zarówno dla Kontraktu, jak i Lokalizacji, a opcje m2m Kontraktu dla Lokalizacji nie są odpowiednio filtrowane według Firmy, którą aktualnie edytujesz.
Krótko mówiąc, potrzebuję opcji administratora, aby zrobić coś takiego:
Ostatecznie nie dbam o to, czy proces filtrowania został umieszczony na podstawowym CompanyAdmin, czy też na ContractInline. (Umieszczenie go w linii jest bardziej sensowne, ale utrudnia odniesienie do podstawowej umowy jako „ja”).
Czy jest ktoś, kto wie o czymś tak prostym, jak ten tak potrzebny skrót? Kiedy tworzyłem administratorów PHP dla tego typu rzeczy, uważano to za podstawową funkcjonalność! W rzeczywistości zawsze był automatyczny i musiał być wyłączony, jeśli naprawdę tego nie chciałeś!
źródło
Bardziej publicznym sposobem jest wywołanie get_form w klasach administracyjnych. Działa również w przypadku pól innych niż bazy danych. Na przykład tutaj mam pole o nazwie „_terminal_list” w formularzu, które może być używane w szczególnych przypadkach do wybierania kilku pozycji końcowych z get_list (żądanie), a następnie filtrowania na podstawie request.user:
źródło