========
Tutorial
========
Lets look at how to write the :doc:`get_started` sample and use the key features.
Initialise nanodjango
=====================
First we import ``nanodjango`` and create a ``Django`` instance:
.. code-block:: python
from nanodjango import Django
app = Django()
The ``Django`` instance, along with the ``nanodjango`` command, performs the magic
needed to make everything work in one file.
We can pass Django settings into the constructor as named keywords. We don't do it above
as nanodjango has sensible defaults, but you can pass in any standard Django setting,
plus some extra ones that nanodjango uses, like ``ADMIN_URL``:
.. code-block:: python
app = Django(
ADMIN_URL="secret_admin/",
SECRET_KEY=os.environ["DJANGO_SECRET_KEY"],
ALLOWED_HOSTS=["localhost", "my.example.com"],
DEBUG=False,
)
For a full list of special nanodjango settings, see :doc:`settings`.
Create a view
=============
In nanodjango a view is a function which is decorated with ``@app.route``:
.. code-block:: python
@app.route("/")
def count(request):
...
The ``@app.route("/")`` decorator serves this view at the url ``/``, and the view
function is passed the request as it would in a normal Django project. You can decorate
both normal and async views in the same way.
From there we can do anything we would in a normal Django view - eg add more decorators,
process the request, use Django forms. We then either return a standard Django
``HttpResponse``, or nanodjango also lets you return a plain string for convenience.
For full details on ``app.route``, including how to specify regular expression paths and
include other urlconfs, see :doc:`views`.
Create an API endpoint
======================
We use `Django Ninja
Number of page loads: {CountLog.objects.count()}
" This just creates an object at every request and reports on how many objects there are, but you could use it with a ``ModelForm`` just like a normal Django model and view. A more complicated example could look like this: .. code-block:: python @app.admin class Author(models.Model): name = models.CharField(max_length=100) birth_date = models.DateField(blank=True, null=True) class AuthorForm(ModelForm): class Meta: model = Author fields = ["name", "birth_date"] @app.route("add/") def add_author(request): form = AuthorForm(request.POST or None) if form.is_valid(): form.save() return "Author added" return render(request, "form.html", {'form': form}) Use the admin site ================== To add a model to the admin site, decorate your models with the ``app.admin`` decorator: .. code-block:: python @app.admin class CountLog(models.Model): ... This decorator also lets you configure your ``ModelAdmin`` by passing class attributes: .. code-block:: python @app.admin( list_display=["id", "timestamp"], readonly_fields=["timestamp"], ) class CountLog(models.Model): ... Using the decorator anywhere in your script will automatically enable the admin site. You can customise the url with ``ADMIN_SITE``, or use the setting to force the admin site to be active even if you're not using the decorator anywhere.: .. code-block:: python app = Django(ADMIN_URL="admin/") Deploy to production ==================== Nanodjango has a built-in command to run your script in production mode, with debug turned off, using whitenoise, gunicorn or uvicorn, and sensible defaults:: nanodjango serve counter.py If you want more control, you can also pass the ``Django`` instance to a WSGI or ASGI server directly: .. code-block:: bash gunicorn -w 4 counter:app uwsgi --module counter:app --processes 4 --http=0.0.0.0:8000 uvicorn counter:app Convert to a full Django project ================================ When you reach the point where you have several views or models, you may want to think about converting your app into a full Django project. You can do this with: .. code-block:: bash nanodjango convert counter.py /path/to/site --name=myproject This will create a Django project at ``/path/to/site/myproject``, and unpack your single file into a full app at ``/path/to/site/myproject/counter``. Your sqlite database, migrations, templates and static files will be copied across, if you have them, and in many cases it should run straight away: .. code-block:: bash cd /path/to/site ./manage.py runserver 0.0.0.0:8000 For full details on how to use nanodjango's ``convert`` command, see :doc:`convert`. Share on the Playground ======================= You can share your script on the `nanodjango.dev