Reputation: 86944
Question : What is the recommended way to specify an initial value for fields if one uses model inheritance and each child model needs to have different default values when rendering a ModelForm
?
Take for example the following models where CompileCommand
and TestCommand
both need different initial values when rendered as ModelForm
.
# ------ models.py
class ShellCommand(models.Model):
command = models.Charfield(_("command"), max_length=100)
arguments = models.Charfield(_("arguments"), max_length=100)
class CompileCommand(ShellCommand):
# ... default command should be "make"
class TestCommand(ShellCommand):
# ... default: command = "make", arguments = "test"
I am aware that one can used the initial={...}
argument when instantiating the form, however I would rather store the initial values within the context of the model (or at least within the associated ModelForm).
What I'm doing at the moment is storing an initial value dict within Meta
, and checking for it in my views.
# ----- forms.py
class CompileCommandForm(forms.ModelForm):
class Meta:
model = CompileCommand
initial_values = {"command":"make"}
class TestCommandForm(forms.ModelForm):
class Meta:
model = TestCommand
initial_values = {"command":"make", "arguments":"test"}
# ------ in views
FORM_LOOKUP = { "compile": CompileCommandFomr, "test": TestCommandForm }
CmdForm = FORM_LOOKUP.get(command_type, None)
# ...
initial = getattr(CmdForm, "initial_values", {})
form = CmdForm(initial=initial)
This feels too much like a hack. I am eager for a more generic / better way to achieve this. Suggestions appreciated.
I now have the following in forms.py
which allow me to set Meta.default_initial_values
without needing extra boilerplate code in views. Default values are used if user does not specify initial={...}
args.
class ModelFormWithDefaults(forms.ModelForm):
def __init__(self, *args, **kwargs):
if hasattr(self.Meta, "default_initial_values"):
kwargs.setdefault("initial", self.Meta.default_initial_values)
super(ModelFormWithDefaults, self).__init__(*args, **kwargs)
class TestCommandForm(ModelFormWithDefaults):
class Meta:
model = TestCommand
default_initial_values = {"command":"make", "arguments":"test"}
Upvotes: 2
Views: 1358
Reputation: 12031
I don't see that much use in setting initial_values on form's meta if you then have to send to the form init.
I would rather create a subclass of ModelForm that overrides the constructor method and then use that subclass as parent class of the other forms.
e.g.
class InitialModelForm(forms.ModelForm):
#here you override the constructor
pass
class TestCommandForm(InitialModelForm):
#form meta
class CompileCommandForm(InitialModelForm):
#form meta
Upvotes: 1