So I have a site where users are capable of registering devices and then registering commands to those devices. These commands have an associated widget (button, slider, etc) that determine the unique properties that the command has.
I am trying to figure out the most generic way to use the model formsets in my application. I have things working, where I create a model_formset for each ModelForm, and get data from each model to place in the formset, and then show it in my template.
What I would really like to do is something like this:
command_formset = modelformset_factory(Command, extra=0, fields='__all__')
formset = command_formset(queryset=Command.objects.filter(device_id=device_id))
Where I get all of my commands (which returns both buttons and sliders) and then make a single command_formset, which has all command objects.
In this case it does part of what I am looking for, where I can query my model and get all button and slider commands, but the formset only includes the fields from command - so the min and max value for the slider are lost.
Is something like this possible? Here is my more complete code:
Models
class Command(models.Model):
command_name = models.CharField(max_length=100)
command = models.CharField(max_length=100)
command_url = models.CharField(max_length=100)
command_type = models.CharField(max_length=100)
device = models.ForeignKey(Device, on_delete=models.CASCADE, default=1) # Each command has one device
def __str__(self):
return self.command_name
class ButtonCommand(Command):
button_color = models.CharField()
class SliderCommand(Command):
min_value = models.IntegerField()
max_value = models.IntegerField()
Forms
class CommandForm(ModelForm):
class Meta:
model = Command
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for field in iter(self.fields):
self.fields[field].widget.attrs.update({'class': 'form-control'})
class ButtonCommandForm(ModelForm):
class Meta:
model = ButtonCommand
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for field in iter(self.fields):
self.fields[field].widget.attrs.update({'class': 'form-control'})
class SliderCommandForm(ModelForm):
class Meta:
model = SliderCommand
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for field in iter(self.fields):
self.fields[field].widget.attrs.update({'class': 'form-control'})
View
command_formset = modelformset_factory(Command, extra=0, fields='__all__')
button_command_formset = modelformset_factory(ButtonCommand, form=ButtonCommandForm, extra=0,
fields=('command_name', 'command', 'command_type', 'command_url'))
slider_command_formset = modelformset_factory(SliderCommand, extra=0,
fields=('command_name', 'command', 'command_type', 'command_url',
'min_value', 'max_value'))
device_form = DeviceForm(initial=device)
formset = command_formset(queryset=Command.objects.filter(device_id=device_id))
button_formset = button_command_formset(queryset=ButtonCommand.objects.filter(device_id=device_id),
prefix="button_form")
slider_formset = slider_command_formset(queryset=SliderCommand.objects.filter(device_id=device_id),
prefix="slider_form")
Edit Additional View Code
template = 'device_control/device_management.html'
return TemplateResponse(request, template, {'device': device,
'device_form': device_form,
'button_formset': button_formset,
'slider_formset': slider_formset,
'formset' : formset})
Another Related Question
input_type = request.POST['command_type']
if input_type == 'button':
form = ButtonCommandForm(request.POST)
elif input_type == 'slider':
form = SliderCommandForm(request.POST)
else:
form = None
Hopefully I am not overwhelming, but the above is a very similar question that seems much simpler. User posts a form, both of which inherit from Command. While the above is quite simple, if I eventually have 20+ different types of CommandForms, this will get fairly nasty.
I am really hoping that I am missing some way that Django can tell which child form should be used to build the form.