Development-only routes in Django
Tags: django, python
Published: 2022-01-23 01:12:38

---
title: Development-only routes in Django
published: true
description: Create conditional routes in a Django project.
tags: django, python
---

When you adopt a continuous integration approach to software development, all of your code gets committed to the main branch of your repository, and that branch must always be in a deployable state. This means you must have a way of hiding incomplete features that aren't ready for your users.

One way to hide incomplete features is to completely omit routes that aren't ready for public viewing on the production site.

## Step 1: Checking if the site is in development

Let's pretend that we're building a project where we are actively working on an incomplete "Blog" feature. The `{project_name}/urls.py` file currently looks like this:

```py
from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path('events/', include('events.urls')),
    path('blog/', include('blog.urls')),
    path('admin/', admin.site.urls),
]
```

We need a way to identify if the site is in development environment. If it's not, then we don't want to include the route.

Django doesn't offer an explicit way of checking development vs production environments, but we know that the `DEBUG` setting in `{project_name}/settings.py` should be set to `False` in production. We'll assume that if `DEBUG` is `True` that we're in development:

```py
from django.contrib import admin
from django.urls import include, path
from django.conf import settings

urlpatterns = [
    path('events/', include('events.urls')), 
    path('blog/', include('blog.urls')
         ) if settings.DEBUG == True else None,
    path('admin/', admin.site.urls),
]
```

Now the `blog/` routes will be accessible in development environments, but they will not be accessible in production.

## Step 2: Filtering out "None" routes (optional)

Surprisingly, Django 3.2 handles items with a value of `None` in the `urlpatterns` list just fine: the code above works as-is. However, my gut tells me this will break _something_ in the future, so I'd prefer to filter all of the `None` values out, leaving only items that have non-None values.

We'll wrap the entire `urlpatterns` list in a `filter` function:

```py
# {project_name}/urls.py

urlpatterns = list(filter(lambda route: route is not None, [
    path('events/', include('events.urls')), 
    path('blog/', include('blog.urls')
         ) if settings.DEBUG == True else None,
    path('admin/', admin.site.urls),
]))
```

The `filter` function must be wrapped in a `list` function, otherwise it will return a filter object. You could also do something similar to this with a list comprehension, but I prefer using `filter` in this case. Alternatively, you could skip this step and everything _should_ still work.

## Next steps

If you wanted to take this further, you could create a reusable `is_development()` function, or use environment variables to check if the app is in production. In my projects, I pass an `APP_ENV` variable into the project on startup, then check it with `os.environ.get('APP_ENV') == "production"`. 

Hopefully you found this post helpful. If you did, feel free to leave a like or a comment.