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 :

  1. Additional field didn't show up in web
  2. 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-

Back to Top