Динамическое обновление мета-класса ModelForm.
-
08-07-2019 - |
Вопрос
С моей точки зрения, я надеюсь динамически обновить встроенный мета-класс ModelForm.Хотя этот код, похоже, обновляет список исключений в классе Meta, выходные данные as_p()
, as_ul()
, и т. д. не отражает обновленное исключение мета.
Я предполагаю, что HTML генерируется при создании ModelForm, а не при создании as_*()
называется.Есть ли способ принудительно обновить HTML?
Это вообще лучший способ сделать это?я просто предположил это должен работа.
Мысли?
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 = []
Решение
Класс Meta используется для динамического создания определения формы, поэтому к моменту создания экземпляра ModelForm поля, не включенные в исключение, уже были добавлены в качестве атрибутов нового объекта.
Обычный способ сделать это — просто иметь несколько определений классов для каждого возможного списка исключений.Но если вы хотите, чтобы сама форма была динамической, вам придется создавать определение класса «на лету».Что-то вроде:
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()
ОБНОВЛЯТЬ:Я только что пересмотрел этот пост и решил опубликовать немного более идиоматический способ обработки динамического класса:
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'))
Другие советы
Другой путь:
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'])
Аналогичный подход, несколько другая цель (общий ModelForm для произвольных моделей):
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)
Использовать modelform_factory
(док):
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