Emma
Diverse decks of slide mainly about Django
By Emmanuelle Delescolle
Source FreeIMG
Source WikiMedia
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. But also more non-Python frameworks (Laravel, Spray, etc...)
Server-rendered-pages was the main thing to have in mind
Rest API's and websockets have become primary concerns
Source pixabay
django-admin startproject splendid
./manage.py startapp core
cookiecutter cordy_project
cookiecutter cordy_app
cookiecutter \
gh:Pylons/pyramid-cookiecutter-starter \
--checkout 2.0-branch
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)
Deck.select().where(Deck.level==2)
class Deck(db.Model):
id = db.Column(db.Integer, primary_key=True)
level = db.Column(db.Integer)
cards = db.Column(JSON)
session.query(Deck).filter(Deck.level==2)
<p>{{object.level}}</p>
{%if object.level == 3 %}
<span>Many points</span>
{%endif%}
from django.conf import settings
print(settings.SOME_VAR)
from simple_settings import settings
print(settings.SOME_VAR)
url_map = [
Route('infos', '/deck/{id}/info', controller='myapp.DeckViewSet', action='info'),
*MyController.get_routes(),
]
class MyController(Controller):
@action(needs_id=False)
def sayhello(self):
return Response('OK')
config.add_route('myroute', '/prefix/{one}/{two}')
config.scan('mypackage')
@view_config(route_name='myroute')
def myview(request):
return Response('OK')
@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"
urlpatterns = [
path('articles/2003/', views.special_case_2003),
path('articles/<int:year>/', views.year_archive),
]
from marshmallow import fields, Schema
class UserCreateSerializer(Schema):
username = fields.String()
password = fields.String()
if request.method == 'GET':
do_something()
elif request.method == 'POST':
do_something_else()
return Response(text="Here's the text of the Web page."')
@click.command()
@click.argument('poll_ids', nargs=-1)
def hello(poll_ids=()):
# do something
IE: fancy name function wrappers
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)
Source flickr
Source WikiMedia
} ->
Copy from Django
->
->
Use "regular" form handling
...
class Handler:
handler = None
_after_response = None
_after_request = None
class Handler:
handler = None
_after_response = None
_after_request = None
def __call__(self, enviro, start):
to_call = Cordy.mapper.match(environ=enviro)
request = Request(enviro)
class Handler:
handler = None
_after_response = None
_after_request = None
def __call__(self, enviro, start):
to_call = Cordy.mapper.match(environ=enviro)
request = Request(enviro)
if to_call is None:
response = HTTPException(404)
class Handler:
handler = None
_after_response = None
_after_request = None
def __call__(self, enviro, start):
to_call = Cordy.mapper.match(environ=enviro)
request = Request(enviro)
if to_call is None:
response = HTTPException(404)
else:
action = to_call.pop('action')
controller_class = to_call.pop('controller')
request.action = action
action = to_call.pop('action')
controller_class = to_call.pop('controller')
request.action = action
try:
controller = import_string(controller_class)(request)
method = getattr(controller, action)
response = method(**to_call)
response = _make_response(response, controller, action)
action = to_call.pop('action')
controller_class = to_call.pop('controller')
request.action = action
try:
controller = import_string(controller_class)(request)
method = getattr(controller, action)
response = method(**to_call)
response = _make_response(response, controller, action)
action = to_call.pop('action')
controller_class = to_call.pop('controller')
request.action = action
try:
controller = import_string(controller_class)(request)
method = getattr(controller, action)
response = method(**to_call)
response = _make_response(response, controller, action)
except BaseHTTPException as http_e:
response = http_e
action = to_call.pop('action')
controller_class = to_call.pop('controller')
request.action = action
try:
controller = import_string(controller_class)(request)
method = getattr(controller, action)
response = method(**to_call)
response = _make_response(response, controller, action)
except BaseHTTPException as http_e:
response = http_e
except WSDisconnect:
return []
action = to_call.pop('action')
controller_class = to_call.pop('controller')
request.action = action
try:
controller = import_string(controller_class)(request)
method = getattr(controller, action)
response = method(**to_call)
response = _make_response(response, controller, action)
except BaseHTTPException as http_e:
response = http_e
except WSDisconnect:
return []
except Exception as e:
response = HTTPException(500, e.args)
def __call__(self, enviro, start):
to_call = Cordy.mapper.match(environ=enviro)
request = Request(enviro)
if to_call is None:
...
else:
try:
response = method(**to_call)
response = _make_response(response, controller, action)
except:
...
self.handler = response
return response(enviro, start)
} ->
Copy from Django
->
->
Use "regular" form handling
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.
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 Python web frameworks
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()
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', ]
class WSController(CordyWSController):
def on_connect(self):
print('WS Connect')
def on_message(self, message):
print('Received message:', message)
def on_receive(self, data):
self.send(data['data'])
def on_disconnect(self):
print('WS Disconnected')
from routes.route import Route
from cordy.crud.controllers import OpenAPIView
from cordy.utils import include
from myapp.controllers import Controller, ToDoViewSet, ToDoHTML
url_map = [
*Controller.get_routes(prefix=''),
Route('websocket', '/ws/', controller='myapp.WSController', action='connect'),
Route('static', "/public/{path_info:.*}", controller='cordy.base.StaticFiles',
action='serve'),
include(ToDoViewSet.get_routes(), '/api/v1'),
include(OpenAPIView.get_routes(prefix='v1', path='/api/v1/'),
'/apidocs'),
include(ToDoHTML.get_routes(prefix='todo'), ''),
]
People involved in Python web are already involved in those libraries
Loss of agency (dependent on library maintainers)
Maintaining a framework as a whole is easier
Resources can be dedicated to the core of the framework
Possible loss of backward compatibility with new library releases
Overall less work needed
Root
Shell
Curry
https://splendid.dev.levitnet.be
By Emma
EuroPython 2021