A model for our JSON

As I have mentioned earlier, one of the biggest benefits of using JSON as the definition format for our forms is that it uses just simple text data to encode the definition of complex objects. While some databases such as PostgreSQL have a column type for JSON, others do not. However, because we are dealing with simple text data, we don't need one! We can store our JSON data in a simple TextField and then encode and decode the data to and from a Python dictionary whenever required. In fact, there are many people in the Django community who have already dealt with this problem and open sourced their solutions for us to use.

One such package that I have used in the past is django-jsonfield. You can find it at https://github.com/bradjasper/django-jsonfield, and we will be using it in our project. First, install the required package by typing the following command in your command line. Make sure to have the virtual environment activated first so that it is installed in the correct location.

> pip install jsonfield

With the package installed, we can create a model for our form. Open up main/models.py and change it to have the following code:

from __future__ import unicode_literals

from django.db import models

from jsonfield import JSONField


class FormSchema(models.Model):
    title = models.CharField(max_length=100)
    schema = JSONField()

Save the file and then create and run migrations so that Django creates the tables for our new model. In the command line, run the following commands:

> python manage.py makemigrations main
Migrations for 'main':
  0001_initial.py:
    - Create model FormSchema
> python manage.py migrate
Operations to perform:
  Apply all migrations: sessions, contenttypes, admin, main, auth
Running migrations:
  Rendering model states... DONE
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying sessions.0001_initial... OK

With the migrations done, let's see how we can use this model. Instead of writing the code for the view, I like to start by doing a bit of experimentation in the Django shell. Open it up by typing as follows:

> python manage.py shell

Then type in the following to test out our new model:

> from main.models import FormSchema
> fs = FormSchema()
> fs.title = 'My First Form'
> fs.schema = {'name': 'string', 'age': 'number', 'city': 'string', 'country': 'string', 'time_lived_in_current_city': 'string'}
> fs.save()
> FormSchema.objects.get(pk=1).schema
{u'age': u'number',
 u'city': u'string',
 u'country': u'string',
 u'name': u'string',
 u'time_lived_in_current_city': u'string'}

What we have done here should be pretty simple for you to understand by now. The important thing to note here is the value that we assigned to the schema field. Instead of using a string representation of the JSON data, we simply assigned a Python dictionary to it. The JSONField class we used as the field class in our model does the heavy lifting of converting from a Python dictionary to a JSON string when saving to the database.

The reverse is also the same. Notice how, in the last line of our shell session, we simply accessed the schema field directly and got a Python dictionary back instead of the string JSON data that is actually saved in the database. This makes working with JSON transparent to us.

Tip

You might be wondering why I am asking you to experiment in this chapter and play around in the shell, whereas in the previous chapters, I just showed you the relevant view/model/template code directly.

Like I mentioned at the start of this chapter, this chapter is about showing you how to arrive at a solution by yourself instead of me holding your hand and showing you the end result immediately.

All good Django developers that I know have a similar method of developing solutions for the projects that they work on. They experiment a bit, and in doing so figure out a solution to the problem they are working on. Everyone has a different way of experimenting though. Some people, like me, use the Django shell a lot. Others write test code in views and models. Others might create simple Django management commands to do the same. However, everyone goes through the same process.

We find a problem that needs to be solved, we research it a bit, and then experiment with the various methods of solving it, finally choosing one which we like the best. You will eventually develop a method that you are comfortable with. In the meanwhile, I'll be walking you through my method and you can use this if you like.

We now have a FormSchema object in our database, so let's create a view that can use this object to generate a form. In main/views.py, first import our new model near the top:

from main.models import FormSchema

Then change the get_form method in our CustomFormView to match this:

def get_form(self):
    form_structure = FormSchema.objects.get(pk=1).schema

    custom_form = forms.Form(**self.get_form_kwargs())
    for key, value in form_structure.items():
        field_class = self.get_field_class_from_type(value)
        if field_class is not None:
            custom_form.fields[key] = field_class()
        else:
            raise TypeError("Invalid field type {}".format(value))

    return custom_form

I have highlighted the new line. We have removed the hardcoded JSON string that we used and instead assigned the schema field's value from our database object to the form_structure variable. The rest of the code stays the same. Try opening the home page for the application again. You'll find that the frontend has stayed the same. The interactions will be the same as well. You can try to submit invalid or incomplete data and it will show you the errors as before. Trying to submit a valid form will still result in the error about success URL not being defined.

Next, let's create a better frontend for our users. We'll create a list view where the user can see a list of all forms available on the site and a form view that displays the actual form and handles the interactions.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.199.184