Specifying different initial values for fields in inherited models (django)

Posted by Shawn Chin on Stack Overflow See other posts from Stack Overflow or by Shawn Chin
Published on 2011-02-02T14:15:24Z Indexed on 2011/02/02 15:26 UTC
Read the original article Hit count: 217

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).

My current approach

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.

Other attempts

I have toyed around with overriding the constructor for the submodels:

class CompileCommand(ShellCommand):
    def __init__(self, *args, **kwargs):
        kwargs.setdefault('command', "make")
        super(CompileCommand, self).__init__(*args, **kwargs)

and this works when I try to create an object from the shell:

>>> c = CompileCommand(name="xyz")
>>> c.save()
<CompileCommand: 123>
>>> c.command
'make'

However, this does not set the default value when the associated ModelForm is rendered, which unfortunately is what I'm trying to achieve.

Update 2 (looks promising)

I now have the following in forms.py which allow me to set Meta.default_initial_values without needing extra code in views.

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"}

© Stack Overflow or respective owner

Related posts about django

Related posts about django-modelforms