Tidbits | Feb. 4, 2023

Pro-Tip – Breaking up django-ninja views

by Frank Wiles |   More posts by Frank

I've been evaluating django-ninja recently, using it in a personal project to see when it might be appropriate for our clients.

The Problem - How to have multiple view files

One thing that was not clear was how to break up your API views and sprinkle them around in multiple files. The default tutorial and documentation is not bad, but just does not cover this small thing.

The way django-ninja works is that you decorate functional views with @api where you indicate what HTTP method it is for and some other parameters. Everything is perfect until you realize your views.py has grown huge or you want to include api views from several Django applications.

For those of us who are very familiar with DRF, it is not immediately clear how you can break your views into multiple files.

Let's use an example of having a Django apps named core, users, and posts to mimic some sort of blog like software and our project directory, which contains our settings and urls files will be named config/ which is the standard way we roll at REVSYS.

Your first guess might be that you should create another instance of NinjaAPI and use that to decorate your views in each file. Unfortunately, because of how the internal registry works for these, that would create multiple django-ninja "sites", each with their own docs, etc. which is obviously not what we want.

The Solution

The easiest way to do this is to pass around your API decorator and ensure your view files are imported before you call on Ninja to generate your URLs.

While I hate having an app named core, I used it in this case. So we create our API instance with the following:

# File: core/api.py
from ninja import NinjaAPI

api = NinjaAPI(csrf=True)

And then in our views we import this and use it:

# File: users/views.py
from core.api import api

@api.get("users/something/"):
def get_user(request):
   # ... do something interesting here ...

# File: posts/views.py
from core.api import api

@api.get("posts/{username}/"):
def get_posts(requests, username: str):
   # ... do something interesting here ...

Then the final bit is to make sure we import these files in our urls.py before we call api.urls like this:

# File: config/urls.py
import users.views
import posts.views
from core.api import api

urlpatterns = [
    path("api/", api.urls),
]

Alternative Solution

Turns out there is also a DRF like concept of routers which is honestly probably a better more maintainable solution than the above.

Thanks to Ville Säävuori for point this out after I posted this.

Hopefully, this saves you a bit of time when you first start using django-ninja!

If you need help creating Django REST APIs don't hesitate to reach out to us!

A simple import trick to make it easy to keep your django-ninja view functions in different Django apps and files.{% else %}

2023-02-04T16:44:00 2023-02-05T15:03:24.814706 2023