Zostało to naprawione w Django 1.9 za pomocą form_kwargs .
Mam formularz Django, który wygląda następująco:
class ServiceForm(forms.Form):
option = forms.ModelChoiceField(queryset=ServiceOption.objects.none())
rate = forms.DecimalField(widget=custom_widgets.SmallField())
units = forms.IntegerField(min_value=1, widget=custom_widgets.SmallField())
def __init__(self, *args, **kwargs):
affiliate = kwargs.pop('affiliate')
super(ServiceForm, self).__init__(*args, **kwargs)
self.fields["option"].queryset = ServiceOption.objects.filter(affiliate=affiliate)
Nazywam ten formularz czymś takim:
form = ServiceForm(affiliate=request.affiliate)
Gdzie request.affiliate
jest zalogowany użytkownik. Działa to zgodnie z przeznaczeniem.
Mój problem polega na tym, że chcę teraz przekształcić tę pojedynczą formę w zestaw form. Nie mogę dowiedzieć się, w jaki sposób mogę przekazać informacje o podmiotach stowarzyszonych do poszczególnych formularzy podczas tworzenia zestawu formularzy. Zgodnie z dokumentacją, aby utworzyć z tego formularz, muszę zrobić coś takiego:
ServiceFormSet = forms.formsets.formset_factory(ServiceForm, extra=3)
A potem muszę to stworzyć w ten sposób:
formset = ServiceFormSet()
Jak mogę przekazać w ten sposób affiliate = request.affiliate do poszczególnych formularzy?
źródło
functools.partial
zamiast Djangodjango.utils.functional.curry
. Robią to samo, z wyjątkiem tego, żefunctools.partial
zamiast zwykłej funkcji Pythona zwracają odrębny wywoływalny typ, apartial
typ nie wiąże się jako metoda instancji, co starannie rozwiązuje problem, który ten wątek komentarza był w dużej mierze poświęcony debugowaniu.Oficjalny sposób dokumentu
Django 2.0:
https://docs.djangoproject.com/en/2.0/topics/forms/formsets/#passing-custom-parameters-to-formset-forms
źródło
Zbudowałbym klasę formularza dynamicznie w funkcji, tak aby miała dostęp do partnera poprzez zamknięcie:
Jako bonus, nie musisz przepisywać zestawu zapytań w polu opcji. Wadą jest to, że podklasy są trochę zabawne. (Każda podklasa musi być wykonana w podobny sposób).
edytować:
W odpowiedzi na komentarz możesz wywołać tę funkcję w dowolnym miejscu, w którym użyjesz nazwy klasy:
źródło
Oto, co zadziałało dla mnie, Django 1.7:
Mam nadzieję, że to komuś pomogło, wystarczająco długo zajęło mi to rozgryzienie;)
źródło
staticmethod
jest tu potrzebny?Podoba mi się rozwiązanie zamykające, które jest „czystsze” i bardziej Pythonic (więc +1 do odpowiedzi mmarshall), ale formularze Django mają również mechanizm wywołania zwrotnego, którego można użyć do filtrowania zestawów zapytań w zestawach formularzy.
Nie jest to również udokumentowane, co moim zdaniem jest wskaźnikiem, że twórcom Django może się to nie podobać.
Więc zasadniczo tworzysz zestaw formularzy tak samo, ale dodajesz wywołanie zwrotne:
To jest tworzenie instancji klasy, która wygląda następująco:
To powinno dać ci ogólny pomysł. Uczynienie wywołania zwrotnego metodą obiektową, taką jak ta, jest nieco bardziej skomplikowane, ale zapewnia nieco większą elastyczność w porównaniu z wykonywaniem prostego wywołania zwrotnego funkcji.
źródło
Chciałem umieścić to jako komentarz do odpowiedzi Carla Meyersa, ale ponieważ wymaga to punktów, po prostu umieściłem go tutaj. Zajęło mi to 2 godziny, więc mam nadzieję, że to komuś pomoże.
Uwaga dotycząca korzystania z pliku inlineformset_factory.
Sam korzystałem z tego rozwiązania i działało idealnie, dopóki nie wypróbowałem go z inlineformset_factory. Używałem Django 1.0.2 i dostałem dziwny wyjątek KeyError. Zaktualizowałem do najnowszego bagażnika i działało bezpośrednio.
Teraz mogę go używać podobnie do tego:
źródło
modelformset_factory
. Dzięki za tę odpowiedź!W dniu zatwierdzenia e091c18f50266097f648efc7cac2503968e9d217 we wtorek 14 sierpnia 23:44:46 2012 +0200 zaakceptowane rozwiązanie nie może już działać.
Bieżąca wersja funkcji django.forms.models.modelform_factory () używa "techniki konstrukcji typu", wywołując funkcję type () w przekazanym formularzu w celu pobrania typu metaklasy, a następnie używając wyniku do skonstruowania obiektu klasy swojego pisz w locie:
Oznacza to, że nawet
curry
ed lubpartial
obiekt przekazany zamiast formularza "powoduje, że kaczka cię ugryzie", że tak powiem: wywoła funkcję z parametrami konstrukcjiModelFormClass
obiektu, zwracając komunikat o błędzie:Aby obejść ten problem, napisałem funkcję generatora, która używa zamknięcia do zwrócenia podklasy dowolnej klasy określonej jako pierwszy parametr, a następnie wywołuje
super.__init__
poupdate
kwargach te podane w wywołaniu funkcji generatora:Następnie w swoim kodzie zadzwonisz do fabryki formularzy jako:
zastrzeżenia:
źródło
Rozwiązanie Carla Meyera prezentuje się bardzo elegancko. Próbowałem go zaimplementować w modelformsets. Miałem wrażenie, że nie mogę wywołać metod statycznych w klasie, ale w niewytłumaczalny sposób działa:
Moim zdaniem, jeśli zrobię coś takiego:
Następnie słowo kluczowe „request” jest propagowane do wszystkich formularzy członkowskich mojego zestawu formularzy. Jestem zadowolony, ale nie mam pojęcia, dlaczego to działa - wydaje się źle. Jakieś sugestie?
źródło
MyFormSet.form.Meta.model
.MyFormSet.form().Meta.model
. Naprawdę oczywiste.Spędziłem trochę czasu próbując rozwiązać ten problem, zanim zobaczyłem ten post.
Rozwiązaniem, które wymyśliłem, było rozwiązanie zamykające (i jest to rozwiązanie, którego używałem wcześniej z formularzami modelowymi Django).
Wypróbowałem metodę curry (), jak opisano powyżej, ale po prostu nie mogłem zmusić jej do pracy z Django 1.0, więc w końcu wróciłem do metody zamknięcia.
Metoda zamykania jest bardzo zgrabna, a jedyną drobną dziwnością jest to, że definicja klasy jest zagnieżdżona w widoku lub innej funkcji. Myślę, że fakt, że wydaje mi się to dziwne, jest rozłączeniem z moim poprzednim doświadczeniem w programowaniu i myślę, że ktoś z doświadczeniem w bardziej dynamicznych językach nie mrugnąłby okiem!
źródło
Musiałem zrobić podobną rzecz. Jest to podobne do
curry
rozwiązania:źródło
na podstawie tej odpowiedzi znalazłem bardziej przejrzyste rozwiązanie:
I uruchom to tak, jak wygląda
źródło
Jestem tu nowicjuszem, więc nie mogę dodawać komentarzy. Mam nadzieję, że ten kod też zadziała:
co do dodawania dodatkowych parametrów do
BaseFormSet
zestawu form zamiast formularza.źródło