vitalik / django-ninja

💨 Fast, Async-ready, Openapi, type hints based framework for building APIs
https://django-ninja.dev
MIT License
7.1k stars 423 forks source link

Change settings access to support FastAPI-style single file apps #1169

Open radiac opened 4 months ago

radiac commented 4 months ago

tl;dr: I would like to import ninja before settings.DEBUG is available, so I can build a Django API in a single file. Are you open to a PR to address this?

I'm the author of nanodjango, a project to write a full Django project in a single file (views, models, admin etc), and then automatically convert it into a normal project structure once it has grown. I'm aiming to make a Flask or FastAPI alternative, with the power and scalability of Django.

A key piece of this is supporting django-ninja - I love the syntax and think they fit really well together. For example, this is a working single-file django project with a model, admin, standard view and a ninja api:

from django.db import models
from nanodjango import Django
django = Django()
from ninja import NinjaAPI
api = NinjaAPI()

@django.admin
class CountLog(models.Model):
    timestamp = models.DateTimeField(auto_now_add=True)

@api.get("/add")
def add(request):
    CountLog.objects.create()

django.route("api/", include=api.urls)

@django.route("/")
def index(request):
    return f"<p>Number of API calls: {CountLog.objects.count()}</p>"

But you'll notice I've run into a problem with import order - django-ninja is testing settings.DEBUG on import (1, 2), but I have no way to configure django's settings until after nanodjango initialises, so I have to import it after that.

I'd really like to make it so that import order doesn't matter, so they can go together naturally at the top of the file and follow pep8.

Would you be open to me submitting a change to ninja.utils.is_debug_server to catch when settings aren't initialised and defer collection until settings are ready? I wouldn't change normal usage, just aim to allow people to import ninja at an unexpected time.

arnoan commented 2 weeks ago

@radiac I just found out about nanodjango via Simon Willisons blog post included in this week's Django newsletter (https://simonwillison.net/2024/Sep/24/nanodjango/?utm_campaign=Django%2BNewsletter&utm_medium=email&utm_source=Django_Newsletter_252) and love the idea of using this approach for fully self-contained small example apps that showcase specific Django and DjangoNinja functionality.

I would prefer to use the official Django Ninja import though so adding native support without violating pep8 or confusing people I wish to demonstrate this to, would be wonderful.

Just wanted to voice my opinion that I feel this issue here adds real value and seems a relatively low hanging fruit to accomplish. Let me know if I can be of support.

vitalik commented 2 weeks ago

Hi @radiac @arnoan

I love nanodjango idea and was brainstorming something similar for a while to be built in into Ninja... (there is actually a great demand for simple single file apps that can do full APIs)

but yeah, I guess I will try the nanodjango as a core and will see where it goes ( at least should glue easely together)

jasalt commented 1 week ago

I had related issue with compatibility using nanodjango's helper attribute https://github.com/radiac/nanodjango/issues/30. Interested in finding a clean working solution.

Currently adding following rule to make ruff ignore the location of the import line.

...
app = Django()
from ninja import NinjaAPI  # noqa: E402
...