How to call form method from template for dynamic form in django
I have a model that one of it's field is CharField, use to store a JSON (list of dictionary) called 'schema'
SCHEMA_DATA_TYPES=(
(1, 'Integer'),
(2, 'String'),
(3, 'Date'),
)
class MailTemplate(models.Model):
name = models.CharField(max_length=20)
tfile = models.FileField(upload_to='uploads/mailtemplate', null=True, blank=True)
schema = models.CharField(max_length=256, blank=True, null=True, editable=False)
def __str__(self) -> str:
return self.name
Currently, it only have one record and the 'schema' value is :
[{"name": "date", "label": null, "type": 2, "format": ""}, {"name": "invoiceNumber", "label": null, "type": 2, "format": ""}, {"name": "company", "label": null, "type": 2, "format": ""}, {"name": "total", "label": null, "type": 2, "format": ""}, {"name": "items", "label": null, "type": 2, "format": ""}]
I need to build a dynamic form that have additional fields contructed from that 'schema' field.
first try I use htmx. The form is showed prefectly, but additional fields couldn't read by forms.py
as suggested by SO user @vinkomlacic at my post How to read additional data posted by form in django forms.py , I serach for doc on how to play with init of form to do it.
I found https://www.caktusgroup.com/blog/2018/05/07/creating-dynamic-forms-django/ looks informative.
so my admin.py is
class MailTemplateAdmin(admin.ModelAdmin):
change_form_template = 'mailtemplate_form.html'
form = MailTemplateForm
admin.site.register(MailTemplate,MailTemplateAdmin)
and mailtemplate_form.html is
{% extends "admin/change_form.html" %}
{% block after_field_sets %}
{% if not add %}
<div id="schema_head">
<b>Schema </b>
</div>
<div id="additional_fields">
{% for schema_line in form.get_schemas %}
{{ schema_line }}
{% endfor %}
</div>
{% endif %}
{% endblock %}
and forms.py have
class MailTemplateForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
schema = self.instance.schema.strip()
#print(f'INSTANCE:{schema}')
schema = json.loads(schema)
for i in range(len(schema)):
self.fields[f'schema_{i}_name'] = forms.CharField(max_length=20, initial=schema[i]['name'])
self.fields[f'schema_{i}_name'].widget.attrs["readonly"] = True
self.fields[f'schema_{i}_label'] = forms.CharField(max_length=20, required = True, initial=schema[i]['label'])
self.fields[f'schema_{i}_type'] = forms.ChoiceField(choices=SCHEMA_DATA_TYPES,initial=schema[i]['type'])
self.fields[f'schema_{i}_format'] = forms.CharField(max_length=20, required = True, initial=schema[i]['format'])
#print(f'FIELDS: {self.fields}')
def get_schemas(self):
print('get_schemas CALLED!')
for s in self.fields:
if s.startswith('schema_'):
yield self.fields[s]
problem is :
- Additional field didn't show up in web
- from console, I didn't see any indications that MailTemplateForm.get_schemas is called.
Kindly please tell me or give me any clue on how to call forms method(s) from template.
Sincerely
-bino-