Aggiorna dinamicamente la classe Meta di ModelForm
-
08-07-2019 - |
Domanda
Spero di aggiornare dinamicamente una classe Meta inline di ModelForm dal mio punto di vista. Sebbene questo codice sembri aggiornare l'elenco di esclusione nella classe Meta, l'output di as_p ()
, as_ul ()
, ecc. Non riflette la Meta exclude aggiornata.
Suppongo quindi che l'html sia generato quando ModelForm non viene creato quando viene chiamato as _ * ()
. C'è un modo per forzare l'aggiornamento dell'HTML?
È anche questo il modo migliore per farlo? Ho appena pensato che questo dovrebbe funzionare.
Pensieri?
from django.forms import ModelForm
from testprogram.online_bookings.models import Passenger
class PassengerInfoForm(ModelForm):
def set_form_excludes(self, exclude_list):
self.Meta.exclude = excludes_list
class Meta:
model = Passenger
exclude = []
Soluzione
La classe Meta viene utilizzata per costruire dinamicamente la definizione del modulo, quindi al momento della creazione dell'istanza ModelForm, i campi non inclusi nell'esclusione sono già stati aggiunti come attributi del nuovo oggetto.
Il modo normale per farlo sarebbe quello di avere solo più definizioni di classe per ogni possibile elenco di esclusione. Ma se vuoi che il modulo stesso sia dinamico, dovrai creare al volo una definizione di classe. Qualcosa del tipo:
def get_form(exclude_list):
class MyForm(ModelForm):
class Meta:
model = Passenger
exclude = exclude_list
return MyForm
form_class = get_form(('field1', 'field2'))
form = form_class()
AGGIORNAMENTO : ho appena rivisto questo post e ho pensato di pubblicare un modo un po 'più idiomatico per gestire una classe dinamica:
def PassengerForm(exclude_list, *args, **kwargs):
class MyPassengerForm(ModelForm):
class Meta:
model = Passenger
exclude = exclude_list
def __init__(self):
super(MyPassengerForm, self).__init__(*args, **kwargs)
return MyPassengerForm()
form = PassengerForm(('field1', 'field2'))
Altri suggerimenti
Un altro modo:
class PassengerInfoForm(ModelForm):
def __init__(self, *args, **kwargs):
exclude_list=kwargs.pop('exclude_list', '')
super(PassengerInfoForm, self).__init__(*args, **kwargs)
for field in exclude_list:
del self.fields[field]
class Meta:
model = Passenger
form = PassengerInfoForm(exclude_list=['field1', 'field2'])
Approccio simile, obiettivo in qualche modo diverso (ModelForm generico per modelli arbitrari):
from django.contrib.admin.widgets import AdminDateWidget
from django.forms import ModelForm
from django.db import models
def ModelFormFactory(some_model, *args, **kwargs):
"""
Create a ModelForm for some_model
"""
widdict = {}
# set some widgets for special fields
for field in some_model._meta.local_fields:
if type(field) is models.DateField:
widdict[field.name] = AdminDateWidget()
class MyModelForm(ModelForm): # I use my personal BaseModelForm as parent
class Meta:
model = some_model
widgets = widdict
return MyModelForm(*args, **kwargs)
Usa modelform_factory
( doc ):
from django.forms.models import modelform_factory
from testprogram.online_bookings.models import Passenger
exclude = ('field1', 'field2')
CustomForm = modelform_factory(model=Passenger, exclude=exclude) # generates ModelForm dynamically
custom_form = CustomForm(data=request.POST, ...) # form instance