Rewriting Django from (almost) scratch
in 2021

By Emmanuelle Delescolle

Who am I?

Why?

  • Review decisions made 15 years ago
  • Explore libraries unavailable/undocumented at the time
  • Build API and Websockets into the main code
  • Thought exercise

Then Vs Now

Source FreeIMG

Source WikiMedia

Then Vs Now

Poor documentation of most libraries

A lot of Python packages are well documented

Little sense of community

Friendly Python community

Rails was the "reference"

Many Python web frameworks to get inspiration from

Lack of tools "in the spirit of Django"

Django inspired many libraries

Server-rendered-pages was the main thing to have in mind

Rest API's and websockets have become primary concerns

Let's go on a tour!

Source pixabay

Tour: Project Template

django-admin startproject splendid
./manage.py startapp core
cookiecutter cordy_project
cookiecutter cordy_app

Tour: ORM

class Deck(Model):
    level = models.IntegerField()
    cards = JSONField()

Deck.objects.filter(level=2)
class Deck(Model):
    level = pw.IntegerField()
    cards = JSONField()

Deck.select().filter(level=2)

Tour: Template engine

<p>{{object.level}}</p>
{%if object.level == 3 %}
  <span>Many points</span>
{%endif%}
<p>{{object.level}}</p>
{%if object.level == 3 %}
  <span>Many points</span>
{%endif%}

Tour: Settings

from django.conf import settings

print(settings.SOME_VAR)
from simple_settings import settings

print(settings.SOME_VAR)

Tour: Routing

from django.urls import path

from myapp.views import InfoView


urlpatterns = [
    path('deck/<uuid:uuid>/info', InfoView.as_view(), name='infos'),
]
from route.route import Route


url_map = [
	Route('infos', '/deck/{id}/info', controller='myapp.DeckViewSet', action='info'),
]

Tour: (De)Serialization

from rest_framework import serializers

class CreateUserSerializer(serializers.Serializer):
    username = serializers.CharField(required=True)
    password = serializers.CharField(required=True)
from marshmallow import fields, Schema

class UserCreateSerializer(Schema):
    username = fields.String()
    password = fields.String()

Tour: Request/Response

if request.method == 'GET':
    do_something()
elif request.method == 'POST':
    do_something_else()

return HttpResponse("Here's the text of the Web page.")
if request.method == 'GET':
    do_something()
elif request.method == 'POST':
    do_something_else()

return Response(text="Here's the text of the Web page."')

Tour: Command-Line

class Command(BaseCommand):
    def add_arguments(self, parser):
        parser.add_argument('poll_ids', nargs='+', type=int)
        
    def handle(self, *args, **options):
        # do something
@click.command()
@click.argument('poll_ids', nargs=-1)
def hello(poll_ids=()):
    # do something

Tour: Middlewares

WSGI middlewares

IE: fancy name function wrappers

Tour: Middlewares

Django Middlewares

class SimpleMiddleware:

    # Same as WSGI middleware
    def __init__(self, get_response):
        self.get_response = get_response
        
    def __call__(self, request):
        # do something with request
        response = self.get_response(request)
        # do something with response
        return response
      
    # Fancy
    def process_view(self, request, view_func, view_args, view_kwargs):
        pass
    
    def process_exception(self, request, exception):
        pass
      
    def process_template_response(self, request, response):
        pass
        

Tour: Special *SGI implementation

to support websockets

def application(env, start_response):
    uwsgi.websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env.get('HTTP_ORIGIN', ''))
    while True:
        msg = uwsgi.websocket_recv()
        uwsgi.websocket_send(msg)

Tour: Form Builder

Put everything in the 

Almost... But not exactly!

blender
and
press power
?

Source flickr

Missing links

Source WikiMedia

Missing Links

  • CSRF
  • Authentication
  • Admin
  • "glue"

Missing Links

  • CSRF
  • Authentication
  • Admin
  • "glue"

} ->

Copy from Django

->

->

Use "regular" form handling

Cordy

What is Cordy?

Annie Cordy

Belgian actress and singer

 

Léonie, Baroness Cooreman, known by the stage name Annie Cordy, was a Belgian actress and singer. She appeared in more than 50 films from 1954. King Albert II of Belgium bestowed upon her the title of Baroness in recognition for her life's achievements.

What is Cordy?

Cordy is a way to rope-in all the libraries and components mentioned before.

 

It is a thought experiment

 

Hopefully it can serve as inspiration for the future of Django

What is Cordy?

from cordy.auth.models import BaseUser, Group
from cordy.db.models import Model

import peewee as pw


class ToDo(Model):

    description = pw.TextField()
    is_done = pw.BooleanField(null=True)


class User(BaseUser):

    groups = pw.ManyToManyField(Group, backref='users')


UserGroup = User.groups.get_through_model() 

models.py example

What is Cordy?

class Controller(CordyController):

    @action(needs_id=False)
    def index(self):
        return HTMLResponse(content="<h1>Hello World</h1>")

      
 class ToDoViewSet(CRUDViewSet):

    Model = ToDo
    pagination_class = PageNumberPagination
    page_size = 2
    filter_fields = ['is_done']
    search_fields = ['description', ]


@authorize_with(AllowAll)
class ToDoHTML(HTMLCRUDViewSet):

    Model = ToDo

    @action(needs_id=False)
    @login_required()
    def index(self, *args, **kwargs):
        return super().index(*args, **kwargs)

controllers.py example 

class WSController(CordyWSController):

    def on_connect(self):
        print('WS Connect')

    def on_receive(self, data):
        self.send(data['data'])

    def on_message(self, message):
        print('Received message:', message)

    def on_disconnect(self):
        print('WS Disconnected')

What is Cordy?

urls.py example 

from routes.route import Route

from cordy.auth.controllers import AuthController
from cordy.crud.controllers import OpenAPIView
from cordy.utils import include

from myapp.controllers import Controller, ToDoViewSet, Routes, ToDoHTML


url_map = [
    *Controller.get_routes(prefix=''),
    *Routes.get_routes(),
    include(ToDoViewSet.get_routes(), '/api/v1'),
    include(OpenAPIView.get_routes(prefix='v1', path='/api/v1/'), '/apidocs'),
    include(ToDoHTML.get_routes(prefix='todo'), ''),
    include(AuthController.get_routes(prefix='auth'), '/api'),
    Route('websocket', '/ws/', controller='myapp.WSController', action='connect'),
    Route('static', "/public/{path_info:.*}", controller='cordy.base.StaticFiles', action='serve'),
]

What is Cordy?

In Action 

What would be the
pros & cons?

People involved in Django are already involved in those libraries

Loss of agency (dependent on library maintainers)

By their existence, these libraries prove their is a want for "Django bits and pieces"

Maintaining Django as a whole is easier

ReWrite needed

Resources dedicated to Django could benefit a wider community

Possible loss of backward compatibility

Overall less work needed

Questions

Root

Shell

Curry

Questions

Rewriting Django from (almost) scratch in 2021

By Emma

Rewriting Django from (almost) scratch in 2021

DjangoCon EU 2021

  • 1,447