Getting Started

Part 1, Chapter 3


Start by creating a new project directory called "taxi-app" to hold both the client and server application.

$ mkdir taxi-app && cd taxi-app

Then, within "taxi-app", create a new virtual environment to isolate our project's dependencies:

$ mkdir django-taxi && cd django-taxi
$ python3.7 -m venv env
$ source env/bin/activate
(env)$

The above commands may differ depending on your OS as well as your Python virtual environment tool (i.e., venv, virtualenvwrapper, Pipenv). If you need a guide, please see here.

Install Django, Django REST Framework, Django Channels, channel_redis, ASGI Redis, Nose, pytest-asyncio, pytest-django, and Pillow, and then create a new Django project and app:

(env)$ pip install \
       channels==2.1.2 \
       channels-redis==2.3.0 \
       Django==2.1 \
       djangorestframework==3.8.2 \
       nose==1.3.7 \
       Pillow==5.2.0 \
       pytest-asyncio==0.9.0 \
       pytest-django==3.4.2
(env)$ django-admin.py startproject example_taxi
(env)$ cd example_taxi
(env)$ python manage.py startapp example

Next, download and install Redis.

If you’re on a Mac, we recommend using Homebrew:

$ brew install redis

In a new terminal window start the Redis server and make sure that it is running on its default port, 6379. The port number will be important when we tell Django how to communicate with Redis.

$ redis-server

Then switch back to your original terminal window. Complete our project's setup by updating INSTALLED_APPS in the settings.py file within your code editor of choice:

# example_taxi/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework', # new
    'example', # new
]

AUTH_USER_MODEL = 'example.User' # new

Here, alongside the boilerplate Django apps, we added Django REST Framework along with our own example app.

We also added an AUTH_USER_MODEL setting to make Django reference a user model of our design instead of the built-in one since we'll need to store more user data than what the standard fields allow.

Since we're creating this project from scratch, defining a custom user model is the right move. If we had made this change later in the project, we would have had to create a supplementary model and link it to the existing default user model.

Create a basic custom user model in the example/models.py file.

# example/models.py
from django.contrib.auth.models import AbstractUser


class User(AbstractUser):
    pass

Then make our first migration:

(env)$ python manage.py makemigrations

Now we can run the Django management migrate command, which will properly set up our app to use our custom user model. All database tables will be created as well.

(env)$ python manage.py migrate

You should see something similar to:

Operations to perform:
  Apply all migrations: admin, auth, contenttypes, example, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0001_initial... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying example.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying sessions.0001_initial... OK

Ensure all is well by running the server:

(env)$ python manage.py runserver

Then, navigate to http://localhost:8000/ within your browser of choice. You should see:

django landing page

Kill the server by typing Control+c (the Control and "c" key at the same time).

Next, configure the CHANNEL_LAYERS by setting a default Redis backend and routing in the settings.py. This can go on the bottom of the file.

# example_taxi/settings.py
REDIS_URL = os.getenv('REDIS_URL', 'redis://localhost:6379')

CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            'hosts': [REDIS_URL],
        },
    },
}

Then, add Django Channels to the INSTALLED_APPS:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'channels', # new
    'example',
]

Try running the server again with python manage.py runserver. You should see the following error:

(env) $ python manage.py runserver
CommandError: You have not set ASGI_APPLICATION, which is needed to run the server.

Create a new file called routing.py within our example_taxi app:

# example_taxi/routing.py
from channels.routing import ProtocolTypeRouter

application = ProtocolTypeRouter({})

Add another new file called asgi.py to example_taxi too (if it's not there already):

# example_taxi/asgi.py
import os
import django
from channels.routing import get_default_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'taxi.settings')
django.setup()
application = get_default_application({})

Open your example/settings.py file one last time. Do you see WSGI_APPLICATION = 'example_taxi.asgi.application' on line 73 or so? Add the following right below it:

# example/settings.py
ASGI_APPLICATION = 'example_taxi.routing.application'

Run with this for now. We'll look at what's happening here in an upcoming lesson.

Make sure the server now runs error-free.

(env) $ python manage.py runserver

There should no longer be any error messages.

Before moving on, take a moment to review all that we've done thus far. Try to answer the "why" along with the "what" and "how". For example, why did we use Redis over an in-memory layer for Django Channels?




Mark as Completed