📜 ⬆️ ⬇️

Dynamic creation of forms based on data from the database in Django

It all started with the fact that it was necessary to often create uniform forms and save the entered data to the database. According to the sute, the form is always the same - “Application for registration” - but depending on the event, the fields in it are different.

The duties of preparing the form had to be passed on to the site administrator, so it was decided to create a form management mechanism through the Django admin interface. This is how the CDBForms application appeared.

The idea is very simple - to create models for describing forms and storing the entered data. Accordingly, the Template models (form Shalon), TemplateField (field in the form template) and FieldParameter (field parameters) for storing information about forms (form templates) and the Record and RecordData models for storing data entered through forms appeared.

Actually:
 class Template (models.Model):
     tag = models.SlugField (max_length = 16, unique = True)
     title = models.CharField (max_length = 50)
    
     def fields (self):
         return TemplateField.objects.filter (template = self) .order_by ('tab')

     def __unicode __ (self):
         return self.title

 class TemplateField (models.Model):
     FieldTypes = (('T', 'Text'), ('B', 'Bool'), ('E', 'E-mail'), ('U', 'URL'), ('C', 'Choices'),)
     template = models.ForeignKey (Template)
     tag = models.SlugField (max_length = 32)
     title = models.CharField (max_length = 50)
     type = models.CharField (max_length = 1, choices = FieldTypes)
     tab = models.IntegerField (default = 0)
     required = models.BooleanField (default = True)

     def __unicode __ (self):
         return u '% s:% s'% (self.template, self.tag)

     def parameters (self):
         return FieldParameter.objects.filter (field = self) .order_by ('tab')
        
     class Meta:
         unique_together = ("template", "tag")
        
 class FieldParameter (models.Model):
     field = models.ForeignKey (TemplateField)
     tag = models.SlugField (max_length = 32)
     value = models.CharField (max_length = 255)
     tab = models.IntegerField (default = 0)

     def __unicode __ (self):
         return u '% s:% s =% s'% (self.field, self.tag, self.value)
        
     class Meta:
         unique_together = ("field", "tag", "value")

 class Record (models.Model):
     template = models.ForeignKey (Template)
     dt = models.DateTimeField ()
    
     def __unicode __ (self):
         return u '% s @% s'% (self.template, self.dt)

 class RecordData (models.Model):
     record = models.ForeignKey (Record)
     field = models.ForeignKey (TemplateField)
     value = models.CharField (max_length = 255)
    
     def __unicode __ (self):
         return u '% s% s'% (self.record, self.field)
        
     class Meta:
         unique_together = ("record", "field")

')
Then it remains only to implement the class of our form:
 class CDBForm (forms.Form):
     def __init __ (self, template = None, tag = None, * args, ** kwargs):
         if template:
             self.template = template
         elif tag:
             self.template = Template.objects.get (tag = tag)
         fields = self.template.fields ()
         for field in fields:
             if field.type == "B":
                 self.base_fields [field.tag] = forms.BooleanField (label = field.title, required = field.required)
             elif field.type == "T":
                 self.base_fields [field.tag] = forms.CharField (label = field.title, required = field.required)
             elif field.type == "C":
                 choices = []
                 for parameter in field.parameters ():
                     if parameter.tag == "choice":
                         choices.append ((parameter.value, parameter.value))
                 self.base_fields [field.tag] = forms.ChoiceField (choices = choices, label = field.title, required = field.required)
             elif field.type == "E":
                 self.base_fields [field.tag] = forms.EmailField (label = field.title, required = field.required)
             elif field.type == "U":
                 self.base_fields [field.tag] = forms.URLField (label = field.title, required = field.required)
         forms.Form .__ init __ (self, * args, ** kwargs)

     def save (self, commit = True):
         data = self.cleaned_data
         if commit:
             rec = Record (template = self.template, dt = datetime.now ())
             rec.save ()
             for k, v in data.iteritems ():
                 f = TemplateField.objects.get (template = self.template, tag = k)
                 d = RecordData (record = rec, field = f, value = v)
                 d.save ()
         return data


The form is ready for use, it remains only to implement a convenient administrator interface. An example of how this works can be found here and here .

You can download the code from code.google.com/p/django-cdbforms
By the way, if someone is interested, I will be glad to cooperate! Thank!

Source: https://habr.com/ru/post/46845/


All Articles