Week 4 | Changes

June 22, 2020

This week, there was discussion within my group about whether MongoDB was a good choice for our data. Data from a learning management system is naturally relational and I spent a good amount of time deciding the relations for MongoDB. Since a RDB made more sense in this case, we decided to switch to PostgreSQL. I already made some decent progress on the Express/MongoDB project and I already had some experience working with Express and PostgreSQL together. Some ORMs that support RDBs were frustrating so I decided to switch to another framework entirely. I liked working with a Python web-framework called Flask so I started in the Python area to look for my next framework.

One feature I liked from my previous application is the ability to generate documentation so that my team members could refer to it. With that feature in mind, I came across a Python framework called FastAPI. FastAPI is a newer framework compared to Django and Flask and it provided automatic documentation generation. I started to working with this framework and it had some features that Express had that I missed with Flask such as routing. Flask provides external routing capabilities through Blueprints, but you can nest them like you can with Express’s router. FastAPI basically has the same routing capabilities with support for middleware. FastAPI also supports serialization and deserialization by using pydnatic and Python’s type system. Through this, FastAPI is able to generate documentation just by doing the basic requirements FastAPI needs in order to run.

With that, I started using FastAPI with SQLAlchemy as the ORM while still using PostgreSQL as the database. Developing with FastAPI proved to be a good experience until I had to deal with a common issue when it comes to Python: circular importing. With pydnatic schemas, you are able to nest them by referring to the class of the schema. With the order of how the schemas were imported, this naturally caused circular import errors. One of the solutions to this problem is to have all the schemas in one file instead of grouped together by model, resulting in a more bloated file. I did not want to do that so I can still be organized. One solution I found is to reference the class using quotes then call update_forward_refs() on the class.

For instance, let’s say we have a Submissions and an Assignments schema and we want to have a list of submissions for the Assignments schema.

#submissions.py
from pydnatic import BaseModel

class Submission(BaseModel):
    pass
# assignments.py
from typing import List
from pydantic import BaseModel

class Assignment(BaseModel):
    submissions: 'List[Submission]'

from .submission import Submission
Assignment.update_forward_refs()

Using this trick for all referenced schemas, I was able to avoid circular importing.

« Week 3
Week 5 »
Back to blog