2010-06-14 7 views
17

Chcę dynamicznie aktualizować Meta.fields. Czy można to zrobić z konstruktora formularzy? Próbowałem następujące, ale year nie pojawia się podczas generowania formularza. Wyświetlane są tylko name i title.Jak dynamicznie aktualizować pola klasy formularza Django Meta z konstruktora formularzy?

class Author(models.Model): 
    name = ... 
    title = ... 
    year = ... 

class PartialAuthorForm(ModelForm): 
    class Meta: 
     model = Author 
     fields = ('name', 'title') 

    def __init__(self, *args, **kwargs): 
     self.Meta.fields += ('year',) 

Odpowiedz

17

Nie, to nie zadziała. Meta została sparodiowana - o dziwo - metaclass, zanim dotrzesz do __init__.

Sposób to zrobić ręcznie dodać boiska self.fields:

def __init__(self, *args, **kwargs): 
    super(PartialAuthorForm, self).__init__(*args, **kwargs) 
    self.fields['year'] = forms.CharField(whatever) 
0

Wewnętrzna klasy Meta już przetworzonych, gdy klasa ModelForm jest tworzony przez metaklasą, która przed utworzeniem wystąpienie. Robienie tego, co próbujesz zrobić w __init__, nie będzie działać tak!
Możesz uzyskać dostęp do utworzonych obiektów pól w dyktafonie self.fields np. możesz zrobić coś takiego, jak self.fields['year'] = forms.MyFormField(...).

4

Odpowiedzi, które mówią, że używają __init__ będą działać, ale utracisz połączenie z modelem (zakładając, że dodawane pole jest w modelu). Zamiast tego możesz dynamicznie tworzyć nową formę, która dziedziczy z istniejącego formularza.

def my_form_factory: 
    class ModifiedAuthorForm(PartialAuthorForm): 
     class Meta(PartialAuthorForm.Meta): 
      fields = PartialAuthorForm.Meta.fields 
      if hasattr(fields, 'append'): 
       fields.append('year') 
      else: 
       fields = fields + ('year',) 
return ModifiedAuthorForm 

Oczywiście jeśli chcesz być wytrzymałe powinieneś sprawdzić, czy pole dodawania nie jest już w fields i powinieneś poradzić exclude również.

14

Odpowiedzi od innych są świetne (zwłaszcza @ BranHandleya), ale czasami najłatwiej jest je warunkowo usunąć. Oczywiście nie działa to w przypadku elementów tworzonych dynamicznie, ale jeśli wystarczy opcjonalnie dołączyć pole lub nie, spróbuj tego w ten sposób.

class MyModelForm(ModelForm): 
    class Meta: 
    model = MyModel 
    fields = ['normalField', 'conditionalField', ] 

    def __init__(self, *args, **kwargs): 

    super(MyModelForm, self).__init__(*args, **kwargs) 

    if condition is True: 
     del self.fields['conditionalField'] 

Wykonanie tego w inny sposób może być dość skomplikowane, jak wskazano powyżej, ale zrzucenie go warunkowo jest całkiem proste. =)

+0

Myślę, że to najbardziej eleganckie rozwiązanie, jak nie straci magię z klasy ModelForms. Ale nie zapomnij wywołać super() w __init__. – bjunix

+0

Ups! Poprawione, dzięki! – mkoistinen

0

Dodanie pola do formularza modelu przez nadpisanie metody __init__ formularza nie będzie działać, ponieważ pola formularza modelu są inicjowane przed wywołaniem konstruktora formularza. Więc nie otrzymasz żadnych wartości od rzeczywistego modelu do formularza, a twoje wartości nie zostaną zapisane w db po wywołaniu zapisu.

Należy użyć pełnego piękno python i użyć klasy dekoratora takiego;)

def year_decorator(form_class): 
    class ModifiedForm(form_class): 
     class Meta(form_class.Meta): 
      if isinstance(form_class.Meta.model, Author): 
       fields = form_class.Meta.fields + ('year',) 
    return ModifiedForm 


@year_decorator 
class PartialAuthorForm(ModelForm): 
    class Meta: 
     model = Author 
     fields = ('name', 'title') 
Powiązane problemy