I have a platform with completely different json configs. Any user can create a new json config that is completely different. Hence I cannot model this staticly.
I am trying to make a dynamic form for these json configs.
Some of the json configs have array of values or objects. Visually, I will need these to be a list of inputs with an 'add more' button.
I see that formsets
are the generally accepted way to add arrays of values in django forms. (I'm already using mysql so I can't switch to postgres ArrayField). However from django examples, multiple formsets are initialized separately and passed into the view.
Since my configs are dynamic, I don't know what formsets to initialize and further, the order of fields intermingle between formsets and the form.
For example I am following this link and creating my form classes dynamically like so:
class FieldHandler():
def __init__(self, fields):
self.formfields = {}
for field in fields:
options = self.get_options(field)
f = getattr(self, "create_field_for_" +
field['type'])(field, options)
self.formfields[field['name']] = f
def get_options(self, field):
options = {}
options['label'] = field['name']
options['help_text'] = field.get("help_text", None)
options['required'] = bool(field.get("required", 0))
return options
def create_field_for_text(self, field, options):
options['max_length'] = int(field.get("max_length", "20"))
return django.forms.CharField(**options)
def create_field_for_number(self, field, options):
options['max_value'] = int(field.get("max_value", "999999999"))
options['min_value'] = int(field.get("min_value", "-999999999"))
return django.forms.IntegerField(**options)
# This does not work, formsets are not shown in the template
def create_field_for_array(self, field, options):
fh = FieldHandler(field['elements'])
form_class = type('DynamicForm', (django.forms.Form,), fh.formfields)
DynamicFormSet = formset_factory(form_class)
return DynamicFormSet(prefix=field['name'])
and in the view:
# arg to FieldHandler is an example config, it will be retrieved from db
fh = FieldHandler([
{'type': 'text', 'label': 'position'},
{'type': 'array', 'label': 'calendar', 'elements': [
{'type': 'text', 'label': 'country'},
{'type': 'text', 'label': 'url'},
]},
{'type': 'number', 'label': 'maxSize'}
])
form_class = type('DynamicForm', (django.forms.Form,), fh.formfields)
form = form_class(request.POST or None)
as you can see, the dynamic form is initialized with a config of position
, an array of calendar
elements and a maxSize
field.
My problem is that my dynamic formset is not being shown in the view at all. If I were to separate the formsets, I would somehow have to insert it somewhere inside the original form, so I can't just iterate over the fields, and dynamically create the form
first, then dynamically create formsets
from the array fields.
Hence I am hoping for a way to dynamically create this type of form, where some fields in the form are formsets
.
How do I do this? Or how should I approach this?
Django is for server-side code, so formsets are static by default, but we can use JavaScript to add some life to them. Before we start slinging some code, let’s take a moment and map out what we need to do to create a dynamic formset. Create an “Add Another Image” button. Clone and insert an new form. Increment the management form.
A formset is a collection of Django Forms. Each formset has a management form which is used to manage the collection of forms contained in it. Formset stores data like the total number of forms, the initial number of forms and the maximum number of forms in a management form.
Django formsets are used to handle multiple instances of a form. One can create multiple forms easily using extra attribute of Django Formsets. In geeks/views.py, The keyword argument extra makes multiple copies of same form. If one wants to create 5 forms enter extra = 5 and similarly for others.
Instead, we use Django's modelformset_factory () which returns a formset class for a given model. modelformset_factory () requires the first argument be the model the formset is for. After specifying the model, different optional arguments can be specified. We'll use two optional arguments - fields and extra .
If you want to save arrays in MySQL you have to do it as JSON, it's the best way to achieve it. Since you want to save a form that the client generates, and probably recover it afterwards, I would do somenthing like:
import json
from django.db import models
class Forms(models.Model):
_forms = models.TextField(null=True)
def get_forms(self):
if self._forms:
return json.loads(self._forms)
return []
def set_forms(self, v):
if not v:
v = []
self._forms = json.dumps(v)
This way when you call it outside it comes as json already and when u want to save it you pass a json to it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With