├── .gitignore ├── requirements.txt ├── hello_world.png ├── hello_django.py ├── hello_django2.py ├── hello_django1.py └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .venv/ 3 | __pycache__/ 4 | .idea -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | asgiref==3.7.2 2 | django==4.2.6 3 | sqlparse==0.4.4 4 | -------------------------------------------------------------------------------- /hello_world.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wsvincent/django-microframework/HEAD/hello_world.png -------------------------------------------------------------------------------- /hello_django.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.core.handlers.wsgi import WSGIHandler 3 | from django.http import HttpResponse 4 | from django.urls import path 5 | 6 | settings.configure( 7 | ROOT_URLCONF=__name__, 8 | ) 9 | 10 | def hello_world(request): 11 | return HttpResponse("Hello, Django!") 12 | 13 | urlpatterns = [ 14 | path("", hello_world) 15 | ] 16 | 17 | application = WSGIHandler() 18 | -------------------------------------------------------------------------------- /hello_django2.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.core.handlers.wsgi import WSGIHandler 3 | from django.core.management import execute_from_command_line 4 | from django.http import HttpResponse 5 | from django.urls import path 6 | 7 | settings.configure( 8 | ALLOWED_HOSTS="*", # new 9 | ROOT_URLCONF=__name__, 10 | ) 11 | 12 | urlpatterns = [path("", lambda request: HttpResponse("Hello, Django!"))] # new 13 | 14 | if __name__ == "__main__": 15 | execute_from_command_line() 16 | else: # new 17 | application = WSGIHandler() 18 | -------------------------------------------------------------------------------- /hello_django1.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.core.handlers.wsgi import WSGIHandler 3 | from django.core.management import execute_from_command_line # new 4 | from django.http import HttpResponse 5 | from django.urls import path 6 | 7 | settings.configure( 8 | ROOT_URLCONF=__name__, 9 | DEBUG=True, # new 10 | ) 11 | 12 | 13 | def hello_world(request): 14 | return HttpResponse("Hello, Django!") 15 | 16 | 17 | urlpatterns = [path("", hello_world)] 18 | 19 | application = WSGIHandler() 20 | 21 | if __name__ == "__main__": # new 22 | execute_from_command_line() 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # µDjango (Django as a Microframework) 2 | 3 | How close can Django get to [Flask's](https://flask.palletsprojects.com/en/3.0.x/quickstart/) five-line "Hello, World!" implementation? 4 | 5 | 6 | 7 | [Carlton Gibson](https://github.com/carltongibson) gave a talk at DjangoCon US 2019, [Using Django as a Micro-Framework](https://www.youtube.com/watch?v=w9cYEovduWI&list=PL2NFhrDSOxgXXUMIGOs8lNe2B-f4pXOX-&index=6&t=0s), where he demonstrated a single file implementation of "Hello, World!" in Django. 8 | 9 | This repo demonstrates his original code example and subsequent attempts to display "Hello, World!" in a single file in as few lines of code as possible. 10 | 11 | ## Set Up 12 | 13 | On the command line navigate to a directory, create and activate a new Python virtual environment, and install Django via `pip`. 14 | 15 | ### Windows _(PowerShell)_ 16 | 17 | ```console 18 | # Windows 19 | $ python -m venv .venv 20 | $ .venv\Scripts\Activate.ps1 21 | (.venv) $ python -m pip install django~=5.0.0 22 | ``` 23 | 24 | ### macOS _or_ GNU/Linux 25 | 26 | ```console 27 | $ python3 -m venv .venv 28 | $ source .venv/bin/activate 29 | (.venv) $ python -m pip install django~=5.0.0 30 | ``` 31 | 32 | ## Option 1: [Carlton Gibson](https://github.com/carltongibson) 33 | 34 | ```python 35 | # hello_django1.py 36 | from django.conf import settings 37 | from django.core.handlers.wsgi import WSGIHandler 38 | from django.http import HttpResponse 39 | from django.urls import path 40 | 41 | settings.configure( 42 | ROOT_URLCONF=__name__, 43 | ) 44 | 45 | def hello_world(request): 46 | return HttpResponse("Hello, Django!") 47 | 48 | urlpatterns = [ 49 | path("", hello_world) 50 | ] 51 | 52 | application = WSGIHandler() 53 | ``` 54 | 55 | Install [Gunicorn](https://gunicorn.org) to run the local server. 56 | 57 | ``` 58 | (.venv) $ python -m pip install gunicorn==22.0.0 59 | ``` 60 | 61 | Start the server. 62 | 63 | ``` 64 | (.venv) $ gunicorn hello_django:application 65 | ``` 66 | 67 | Navigate to [http://127.0.0.1:8000](http://127.0.0.1:8000). To stop the Gunicorn server, use `Ctrl+c` on the command line. 68 | 69 | ## Option 2: [Peter Baumgartner](https://github.com/ipmb) 70 | 71 | Peter offered an update using `execute_from_command_line` to make `python hello_django.py` the equivalent of running Django's `manage.py` command. It also does not need `Gunicorn` to be installed. 72 | 73 | ```python 74 | # hello_django2.py 75 | from django.conf import settings 76 | from django.core.handlers.wsgi import WSGIHandler 77 | from django.core.management import execute_from_command_line # new 78 | from django.http import HttpResponse 79 | from django.urls import path 80 | 81 | settings.configure( 82 | ROOT_URLCONF=__name__, 83 | DEBUG=True, # new 84 | ) 85 | 86 | def hello_world(request): 87 | return HttpResponse("Hello, Django!") 88 | 89 | urlpatterns = [ 90 | path("", hello_world) 91 | ] 92 | 93 | application = WSGIHandler() 94 | 95 | if __name__ == "__main__": # new 96 | execute_from_command_line() 97 | ``` 98 | 99 | Then start the server with Django's `runserver` command. 100 | 101 | ``` 102 | (.venv) $ python hello_django1.py runserver 103 | ``` 104 | 105 | And navigate to [http://127.0.0.1:8000](http://127.0.0.1:8000). 106 | 107 | ## Option 3: [Paolo Melchiorre](https://github.com/pauloxnet) 108 | 109 | Paolo further decreased the size of the file using `lambda` instead of the function, reduced the memory usage using `ALLOWED_HOSTS` instead of `DEBUG`, and made it possible to use the code with `runserver` or `gunicorn`. 110 | 111 | ```python 112 | # hello_django2.py 113 | from django.conf import settings 114 | from django.core.handlers.wsgi import WSGIHandler 115 | from django.core.management import execute_from_command_line 116 | from django.http import HttpResponse 117 | from django.urls import path 118 | 119 | settings.configure( 120 | ALLOWED_HOSTS="*", # new 121 | ROOT_URLCONF=__name__, 122 | ) 123 | 124 | urlpatterns = [path("", lambda request: HttpResponse("Hello, Django!"))] # new 125 | 126 | if __name__ == "__main__": 127 | execute_from_command_line() 128 | else: # new 129 | application = WSGIHandler() 130 | ``` 131 | 132 | ### Run 133 | 134 | #### `runserver` 135 | 136 | Start the server with Django's `runserver` command. 137 | 138 | ```console 139 | (.venv) $ python hello_django2.py runserver 140 | ``` 141 | 142 | #### `gunicorn` 143 | 144 | Install [Gunicorn](https://gunicorn.org) to run the local server. 145 | 146 | ``` 147 | (.venv) $ python -m pip install gunicorn==21.2.0 148 | ``` 149 | 150 | Start the server with the `gunicorn` command. 151 | 152 | ```console 153 | (.venv) $ gunicorn hello_django2:application 154 | ``` 155 | 156 | ### Test 157 | 158 | Navigate to [http://127.0.0.1:8000](http://127.0.0.1:8000). 159 | 160 | To stop the `runserver` or `gunicorn`, use `Ctrl+c` on the command line. 161 | 162 | ## Option 3b: [Paolo Melchiorre](https://github.com/pauloxnet/uDjango) 163 | 164 | At the DjangoCon US 2023 sprints, Paolo presented a new version of this file that uses ASGI and [uvicorn](https://www.uvicorn.org/) to return the JSON response "Hello World". 165 | 166 | Install `uvicorn` along with the existing Django installation. 167 | 168 | ``` 169 | (.venv) $ python -m pip install uvicorn 170 | ``` 171 | 172 | Create a new file called `hello_django3.py` and update it as follows: 173 | 174 | ```python 175 | # hello_django3.py 176 | from django import conf, http, urls 177 | from django.core.handlers.asgi import ASGIHandler 178 | 179 | conf.settings.configure(ALLOWED_HOSTS="*", ROOT_URLCONF=__name__) 180 | 181 | app = ASGIHandler() 182 | 183 | 184 | async def root(request): 185 | return http.JsonResponse({"message": "Hello World"}) 186 | 187 | 188 | urlpatterns = [urls.path("", root)] 189 | ``` 190 | 191 | Start the server with the `uvicorn` command: 192 | 193 | ``` 194 | (.venv) $ uvicorn hello_django3:app --reload 195 | ``` 196 | 197 | Open your browser at `http://127.0.0.1:8000` and the JSON response is: 198 | 199 | ``` 200 | { "message": "Hello World" } 201 | ``` 202 | 203 | 204 | ## Option 4: [Andrew Godwin](https://github.com/andrewgodwin/django-singlefile) 205 | 206 | In March 2024, Andrew Godwin released a small library that makes it easier to write single-file Django applications in a similar way to how you'd write Flask applications. First, install the library. 207 | 208 | ``` 209 | (.venv) $ python -m pip install django-singlefile 210 | ``` 211 | 212 | Then create a file called `hello_django4.py` with the following code: 213 | 214 | ```python 215 | # hello_django4.py 216 | from django.http import HttpResponse 217 | from django.singlefile import SingleFileApp 218 | 219 | app = SingleFileApp() 220 | 221 | 222 | @app.path("") 223 | def index(request): 224 | name = request.GET.get("name", "World") 225 | return HttpResponse(f"Hello, {name}!") 226 | 227 | 228 | if __name__ == "__main__": 229 | app.main() 230 | ``` 231 | 232 | To run the app you can call it from the command line: 233 | 234 | ``` 235 | (.venv) $ python hello_django4.py runserver 236 | ``` 237 | --------------------------------------------------------------------------------