Importing data with Django Ninja's ModelSchema

I have recently been playing with Django Ninja for small APIs and for leveraging Schema. Specifically, ModelSchema is worth checking out because it’s a hidden gem for working with Django models, even if you aren’t interested in building a Rest API.

Schemas are very useful to define your validation rules and responses, but sometimes you need to reflect your database models into schemas and keep changes in sync. https://django-ninja.dev/guides/response/django-pydantic/

One challenge we face is importing data from one legacy database into a new database with a different structure. While we can map old fields to new fields using a Python dictionary, we also need more control over what the data looks like coming back out.

Thankfully, ModelSchema is built on top of Pydantic’s BaseModel and supports Pydantic’s Field alias feature.

This allows us to create a ModelSchema based on a LegacyCategory model, and we can build out Field(alias="...") types to change the shape of how the data is returned.

We can then store the result as a Python dictionary and insert it into our new model. We can also log a JSON representation of the instance to make debugging easier. See Serializing Outside of Views for an overview of how the from_orm API works.

To test this, I built a proof of concept Django management command using django-click, which loops through all our legacy category models and prints them.

# management/commands/demo_model_schema.py
import djclick as click

from ninja import ModelSchema
from pydantic import Field

from legacy.models import LegacyCategory
from future.models import Category


class LegacyCategorySchema(ModelSchema):
    name: str = Field(alias="cat_name")
    description: str = Field(alias="cat_description")
    active: bool = Field(alias="cat_is_active")

    class Meta:
        fields = ["id"]
        model = Category


@click.command()
def main():
    categories = LegacyCategory.objects.all()
    for category in categories:
        data = LegacyCategorySchema.from_orm(category).dict()
        print(data)
        # save to a database or do something useful here

More resources

If you are curious about what Django Ninja is about, I recommend starting with their CRUD example: Final Code, and working backward. This will give you a good idea of what a finished CRUD Rest API looks like with Django Ninja.

Jeff Triplett @webology