This week, after last week’s dockerizing marathon, we set out to restore all of our existing backend functionality (including forms) which were temporarily commented out to avoid unnecessary errors whilst dockerizing. We haven’t set ourselves the task of completely building out the backend, but we want to implement at least the beginning of the functionality that was going to be required.

Restoring Existing Functionality

Migrations Issues

As easy as this sounds, this was the week we were given a baptism of fire in errors, relating to changes that restoring existing functionalities had on the database migrations file that was auto generated by Django (migrations.py). For days on end, we were given the cryptic error: django.db.utils.ProgrammingError: relation "relation_name" does not exist.

Eventually, we realised that this issue stemmed from the fact that there were conflicting database structures configured in the migrations.py file and in our local database volumes. Hence, at any instance that we had made a change to a field in a Django Model that we had defined, resulting in us having to run python manage.py makemigrations and python manage.py migrate, we hit a dead end.

As we identified the root cause of the problem, we realised that we had a choice to make ahead:

  • Keep the state of the migrations in src/.
  • Remove the previous volumes and rebuild every time that we wanted to make changes.

We decided on the latter, as we thought the former to be a bad development practise and decided that one the application was in production, we would no longer need to make changes to the database or its structure as everything would have been implemented and thoroughly tested, meaning that the volumes we had we could preserve.

Removing the volumes after each change though, given the number of relations that we had in the database, would mean having to add them back in a new form for later testing and development - a process that would be very long and tedious. Accordingly, we sought after doing one of the things Computer Scientist’s do best: automating the process.

Django ORM and Automating Database Population

To automate the database population, we used Django’s ORM (Object Relational-Mapper) and a python script in the style of the rest of the project to populate the database. We also used this opportunity to make migrations for both of the apps. This too was rather monotonous, but much better than the alternative and will almost certainly save us a lot of time in future. A snippet of the file is shown here:

def insert_dummy_data():
    shoulder_1 = Group.objects.create(name="Shoulder Therapy 1")
    hip_1 = Group.objects.create(name="Hip Therapy 1")

    press_up_tasks = [Task.objects.create(title="Perform 20 Press-Ups", group=shoulder_1, due_date=datetime.datetime(2020, 1, i), due_time=datetime.time(10 + i, 0)) for i in range(1,4)]

    questions = []
    for task in press_up_tasks:
        for number in [10, 20, 30]:
            questions.append(Question.objects.create(task=task, link="https://www.url.com", description="Do " + str(number) + " Push-Ups", response_type=1))

Fortunately, after we had done all of this, we were able to restore existing functionality (we were able to create new forms, add forms to the database, create tasks and questions).

Next Steps

Unfortunately the poor documentation of the issue defined above in conjunction with our lack of experience with these technologies meant that the time taken to resolve the issue above was far greater than it should otherwise have been - meaning we essentailly lost a week of development (everybody’s local machine had the same error).

Next week we hope to seriously continue the backend implementation and integration, making a large part (if not the majority of the existing frontend framework) fully functional, allowing us to take a big step towards user testing.