Skip to main content

File system based routing for Django & Flask

Project description

File Routes

File system based routing for Python Web Frameworks, currently supporting Django

This project has been inspired by the next.js routing.

Background

The purpose of this project is to investigate if there's a way to make it easier to add and write new views.

The path part of the URL was originally modelled after a unix path (/foo/bar/baz), where each component is separated by a '/' (slash). In a web framework you typically have one or several files that contains views. Why not combine the both?

To be able to efficiently map a url path to a filename in Python, the following rules must be followed:

  1. All routes should go in one directory, by default called routes/.
  2. init.py files should be ignored in the path lookup as it
  3. If you want to map the root, create a file called index.py, a side-effect is that it's not possible to create a route containing index

For instance:

URL path Filename
/ routes/index.py
/home routes/home.py
/users/ routes/user/index.py
/users/settings routes/user/settings.py

For wildcards there are some differences between frameworks, but the general idea is:

URL path Filename
/<str:name> routes/[str_name].py
/<uuid:user_id>/settings routes/[uuid_user_id]/settings.py
/users/ routes/user/index.py
/users/settings routes/user/settings.py

For large projects it's a good practice to write one view per file, to avoid making it hard to find a specific view. If you follow that you will have to duplicate the name of the view many times:

For example, in Django you would do something like this:

In views/authenticate.py:

from django.http.request import HttpRequest
from django.http.response import HttpResponse


def authenticate(request: HttpRequest) -> HttpResponse:
    ...
    return HttpResponse(...)

In urls.py:

from django.urls import path

from views.authenticate import authenticate  # noqa

urlpatterns = [
    path("authenticate", authenticate, name="authenticate")
]

In the example above you end up duplicating the view name 7 times:

# Description Code
1 The filename of the view authenticate.py
2 The name of the view def authenticate(...):
3 The module name in urls.py from views.authenticate import ...
4 The function name in urls.py from views.... import authenticate
5 The route url path('authenticate', ...)
6 The imported view path(..., authenticate, ...)
7 The route name path(..., ..., name='authenticate')

Note: While not recommended, you can avoid duplicating some of them if you don't follow best practices, for instance using multiple views per file, using * imports or avoding reverse(...).

Getting started

To use file-routes, you would currently need to use Django or Flask, support for more frameworks (e.g FastAPI) is planned.

For Django:

pip install file-routes[django]

For Flask:

pip install file-routes[flask]

That's it!

Django Tutorial

In urls.py:

from django.urls import path

from file_routes.frameworks.django import autodiscover

urlpatterns = [
 path("", autodiscover())
]

By default, autodiscover will scan for routes in the routes directory.

Create a new directory views in your django project and call it routes/authenticate.py:

from django.http.request import HttpRequest
from django.http.response import HttpResponse

def view(request: HttpRequest) -> HttpResponse:
    ...
    return HttpResponse("Hello World!")

And that's it, you can now access this at via the URL: /authenticate and also via reverse("authenticate")

If you rename the filename to login.py, the url and route name will automatically update.

Quick Video

Video script

  1. Create a new project in PyCharm
  2. Install via pip install
  3. Add to INSTALLED_APPS
  4. Create a new file
  5. Access the file via a web browser

Tests

Tutorial

Supported Python and Web framework versions

Currently only Django 4.1 and Python 3.11 has been tested, but it is likely to work in older versions as well, with perhaps minimal tweaks.

System Checks Reference

To aid users and make it easier to debug common issues, file-routes extends the System check framework in Django and adds the following checks

  • fileroutes.W001 view must be a function
  • fileroutes.W002 view must be a class
  • fileroutes.W003 view must be a subclass of django.views.View
  • fileroutes.W004 cannot find view in module
  • fileroutes.W005 invalid view name
  • fileroutes.W006 route_kwargs must be a dict
  • fileroutes.W007 route_name must be a str

To silence one or several system checks use the SILENCED_SYSTEM_CHECKS setting.

Settings

The default directory for the routes is called routes, this can be changed by adding this to your Django settings.py:

In settings.py:

FILE_ROUTES_DIRECTORY = "routes"

Roadmap

MVP

This is a list of tasks that should be finished before doing the first version and announcing

  • unit tests: test errors
  • document
  • Error multiple views with the same name: foo.py/foo
  • common decorators (csrf_enforce etc) for all views

Future

  • lazy loading?
  • django: reload routes without manual restart
  • Serve pretty root page with HTML docs?

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

file_routes-0.1.6-py3-none-any.whl (14.2 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page