Open mofr opened 2 years ago
I'm trying to incapsulate django usage within winter_django package by creating a winter_django.create_wsgi
function which sets up the application and returns ready-to-work WSGI instance.
https://github.com/WinterFramework/winter/tree/winter-django-wsgi
https://github.com/WinterFramework/winter-getting-started/tree/winter-django-wsgi
Temporarily missing functionality:
OpenAPI resolution plan:
EDIT: Moved to a separate issue https://github.com/WinterFramework/winter/issues/241
Better version of WinterWebApplication:
import winter.core
from injector import Injector
class WinterWebApplication:
"""
Generic class to be incorporated into Winter framework.
Performs basic autodiscovery and injector setup.
Hides drf_yasg usage and simplifies the application setup.
It's also supposed to absorb all global configurations from winter except annotations which are static.
"""
class DjangoURLConf:
def __init__(self):
self.urlpatterns = []
def __init__(self, routes_package: str, injector_modules):
"""
:param routes_package: TODO Make it optional, discover the current directory by default
:param injector_modules:
"""
# It's public for the only purpose - to integrate it with existing Django app
self.django_urlconf = self.DjangoURLConf()
self._setup_django(self.django_urlconf)
winter.core.set_injector(Injector(injector_modules))
winter.web.setup()
self._autodiscover_routes(routes_package)
def _setup_django(self, urlconf: DjangoURLConf):
from django.conf import settings
settings.configure(
ROOT_URLCONF=urlconf,
REST_FRAMEWORK={
'DEFAULT_RENDERER_CLASSES': ('winter_django.renderers.JSONRenderer',),
'UNAUTHENTICATED_USER': object,
},
INSTALLED_APPS=(
# Hack for making module discovery working
'django.contrib.admin',
'django.contrib.contenttypes',
# End hack
),
SWAGGER_SETTINGS={
'DEFAULT_AUTO_SCHEMA_CLASS': 'winter_openapi.SwaggerAutoSchema',
}
)
import django
import winter_django
import winter_openapi
winter_django.setup()
winter_openapi.setup(allow_missing_raises_annotation=True)
django.setup()
def _autodiscover_routes(self, package: str):
import winter_django.autodiscovery
self.django_urlconf.urlpatterns = winter_django.autodiscovery.create_django_urls_for_package(package)
def get_wsgi(self):
from django.core.wsgi import get_wsgi_application
return get_wsgi_application()
def get_openapi(self, title: str, format: str = 'json') -> str:
from drf_yasg.generators import OpenAPISchemaGenerator
from drf_yasg import openapi
api_info = openapi.Info(title=title, default_version='v1')
generator = OpenAPISchemaGenerator(api_info, urlconf=self.django_urlconf)
schema = generator.get_schema()
if format == 'json':
from drf_yasg.codecs import OpenAPICodecJson
codec = OpenAPICodecJson(validators=[], pretty=True)
swagger_json = codec.encode(schema).decode('utf-8')
return swagger_json
elif format == 'yaml':
from drf_yasg.codecs import OpenAPICodecYaml
codec = OpenAPICodecYaml(validators=[])
swagger_yaml = codec.encode(schema).decode('utf-8')
return swagger_yaml
And example usage:
from injector_modules.sqlalchemy_engine import SQLAlchemyEngineModule
from injector_modules.database_url import DatabaseUrlModule
# injector modules to be automatically discovered as well
app = WinterWebApplication('api', injector_modules=[
SQLAlchemyEngineModule,
DatabaseUrlModule,
])
wsgi = app.get_wsgi()
openapi = app.get_openapi(title='My API', format='json')
Pain points (as shown by the winter-getting-started project):
Django-related:
django-admin startproject
which generates a lot of visible boilerplate and clutterrest_framework
to INSTALLED_APPScreate_django_urls_for_package
DEFAULT_RENDERER_CLASSES
ALLOWED_HOSTS
before deploymentDJANGO_SETTINGS_MODULE
django.setup
LiveServerTestCase
(replaced with httpx)SWAGGER_SETTINGS
STATIC_ROOT
drf_yasg
toINSTALLED_APPS
whitenoise
Not related to Django:
@winter.web.no_authentication