Tutorial

You can use this tutorial to start a new project or integrate aiohttp application into your Django project.

Start project

Start you project using django-admin startproject command:

$ mkdir tutorial
$ cd tutorial
$ pyvenv venv
$ . venv/bin/activate
$ pip install django aioworkers
$ django-admin startproject tutorial .

Project structure will look like this:

tutorial/
├── manage.py
├── tutorial
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── venv

Install dvhb-hybrid:

$ pip install git+https://github.com/dvhb/dvhb-hybrid

Create an application

Generally, Django project consists of a few applications.

For instance, we need to create a GET /users method which returns a list of the application’s users. So create a users django application and place it as a subpackage of the tutorial package:

$ mkdir tutorial/users
$ django-admin startapp users tutorial/users

Now we can declare the User model in users/models.py by extending django.contrib.auth.models.AbstractUser:

from django.contrib.auth.models import AbstractUser


class User(AbstractUser):
    pass

It’s necessary to create a tutorial/users/amodels.py with User model based on dvhb_hybrid.amodels.Model. It needs to work with the model from asyncio. This model will be loaded by dvhb_hybrid.amodels.AppModels and used to access the data from async functions.

from dvhb_hybrid.amodels import Model

from .models import User as DjangoUser

class User(Model):
    # Create SQLAlchemy table based on Django table
    table = Model.get_table_from_django(DjangoUser)

Let’s add an async function which will be using our model in module tutorial/users/views.py:

async def get_users(request):
        return await request.app.m.user.get_list(fields=['username', 'email'])

Our aiohttp application uses SwaggerRouter from aiohttp_apiset to build application routes and we need to specify our endpoint as swagger spec here tutorial/users/users_api.yaml:

paths:
  '':
    get:
      $handler: tutorial.users.views.get_users
      tags:
        - user
      summary: Users list
      description: Returns list of users

      produces:
        - application/json

      responses:
        200:
        description: OK

Configuring of project

You can configure the project in any way you like. But we suggest to use common config for your Django Admin and aiohttp application. It allows you to avoid duplication of parameters.

For instance, an application can be configured using load_conf function from aioworkers.config. Create a config.yaml in the base folder and specify the database configuration and some other parameters required by aioworkers:

Load configuration to settings.py and use it to build Django DATABASES:

from dvhb_hybrid.config import load_conf, db_to_settings

...

config = load_conf(os.path.abspath(os.path.join(BASE_DIR, 'config.yaml')))

...

DATABASES = db_to_settings(config.databases, BASE_DIR)

Add our users application to settings.py:

...

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'tutorial.users',
]

AUTH_USER_MODEL = 'users.User'

...

Create DB, make the migrations and migrate it:

$ createdb tutorial
$ python manage.py makemigrations
$ python manage.py migrate

Now you can create a super user for your application:

$ python manage.py createsuperuser --username admin --email admin@example.com

Run Django Administration and login here using the username and password specified in previous step:

$ python manage.py runserver

Create an asyncio application

Add tutorial/api.yaml with specification from users application:

swagger: '2.0'

basePath: /api

info:
  title: TUTORIAL API
  version: '1.0'
  description: API версии 1.0

paths:
  /users:
    - $include: users/users_api.yaml

Create tutorial/app.py:

 import os

 import aiopg.sa
 import django
 from aiohttp_apiset import SwaggerRouter
 from aiohttp_apiset.middlewares import jsonify
 import aioworkers.http

 from dvhb_hybrid.amodels import AppModels

 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tutorial.settings")
 django.setup()

 import tutorial
 AppModels.import_all_models_from_packages(tutorial)


 class Application(aioworkers.http.Application):
     def __init__(self, *args, **kwargs):
         router = SwaggerRouter(search_dirs=['tutorial'])
         kwargs['router'] = router

         kwargs.setdefault('middlewares', []).append(jsonify)

         super().__init__(**kwargs)

         router.include('api.yaml')

         cls = type(self)
         self.on_startup.append(cls.startup_database)
         self.on_cleanup.append(cls.cleanup_database)

     async def startup_database(self):
         dbparams = self.config.databases.default
         self['db'] = await aiopg.sa.create_engine(**dbparams)
         self.models = self.m = AppModels(self)

     async def cleanup_database(self):
         self['db'].close()
         await self['db'].wait_closed()



So now we can run an application:
$ python -m aioworkers -c config.yaml

This will run the application on localhost:8080 with Swagger UI here http://localhost:8080/apidoc/.

Test API via curl:

$ curl -X GET http://localhost:8080/api/users
[{"username": "admin", "email": "admin@example.com"}]

Final project structure will look like this:

tutorial/
├── config.yaml
├── manage.py
├── tutorial
│   ├── __init__.py
│   ├── api.yaml
│   ├── app.py
│   ├── settings.py
│   ├── urls.py
│   ├── users
│   │   ├── __init__.py
│   │   ├── amodels.py
│   │   ├── apps.py
│   │   ├── migrations
│   │   │   ├── 0001_initial.py
│   │   │   ├── __init__.py
│   │   ├── models.py
│   │   ├── tests.py
│   │   ├── users_api.yaml
│   │   └── views.py
│   └── wsgi.py