Mettre à jour dynamiquement la classe Meta de ModelForm
-
08-07-2019 - |
Question
J'espère mettre à jour de manière dynamique la classe Meta en ligne de ModelForm depuis mon écran. Bien que ce code semble mettre à jour la liste d'exclusion de la classe Meta, la sortie de as_p ()
, as_ul ()
, etc. ne reflète pas l'exclusion Meta mise à jour.
Je suppose alors que le code HTML est généré lorsque le ModelForm est créé et non lorsque le as _ * ()
est appelé. Existe-t-il un moyen de forcer la mise à jour du code HTML?
Est-ce même la meilleure façon de le faire? Je viens de supposer que cela devrait fonctionner.
Pensées?
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 = []
La solution
La classe Meta est utilisée pour construire dynamiquement la définition du formulaire. Ainsi, au moment où vous avez créé l'occurrence de ModelForm, les champs non inclus dans l'exclusion ont déjà été ajoutés en tant qu'attributs du nouvel objet.
La façon habituelle de procéder consiste simplement à avoir plusieurs définitions de classe pour chaque liste d'exclusion possible. Mais si vous voulez que le formulaire soit dynamique, vous devez créer une définition de classe à la volée. Quelque chose comme:
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()
MISE À JOUR : je viens de revoir ce post et je pensais poster un moyen un peu plus idiomatique de gérer une classe dynamique:
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'))
Autres conseils
Autre moyen:
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'])
Approche similaire, objectif quelque peu différent (ModelForm générique pour les modèles arbitraires):
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)
Utilisez 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