Optimal project structure for Django-based single-page apps

2017-09-18 by Senko Rašić

Each platform or framework usually has a preferred, best practice, or mandated project structure. When the project combines several frameworks, for example Django and one of the modern JavaScript frameworks, it's unclear how to organize the code. Often, whichever structure is more natural to the developer(s) is used, defaulting to the one in the framework the developer(s) work with more.

This might not be optimal, and may involve fudging the other framework build processes to fit into the structure of the "main" one. This gets harder as more opinonated frameworks or elaborate scaffolding tools are used.

In our work on such projects at GoodCode, we take an alternative approach: each framework's project structure is what's best practice for that framework, and all of them are subdirectories of the project root.

Here's an example from a recent project involving Django-based backend, and Vue.js-based frontend using webpack:

app/
    README.md
    Makefile
    backend/
        README.md
        manage.py
        requirements.txt
        project/
            ...
        core/
            ...
        api/
            ...
    ui/
        README.md
        package.json
        package.lock
        src/
            ...
        test/
            ...
        build/
            ...
        config/
            ...
        static/
            ...
        node_modules/
            ...

The project root contains the documentation pertaining to the entire project. The back-end part has its own backend directory with our typical Django setup. In this case, it's a simple service so we split it in two parts, core (providing the business logic and model layer) and api (providing RESTful API) apps, while project is the directory for the Django project itself (containing settings and the like).

The front-end part follows a recommended layout and was in this case scaffolded using vue-cli with webpack template. The src and test directories contain front-end source code and the tests, config holds the build configuration, build is the output directory, static contains the static files and all dependencies get installed to node_modules.

We also have a root-level Makefile which defines the build actions and connects the components: for example, automatically copying the ui build output to an appropriate place from which it can be collected during collectstatic Django management command. Alternative approach is adding the build directory to STATICFILES_DIRS in Django, though that couples the components a bit.

This project structure ensures a clean separation of the two very different components and is comfortable for both the back-end and front-end developers: their part of the picture is familiar, and they know exactly what not to touch. It also allows us to take advantage of the scaffolding ant other tools to speed up development, since we can follow the best practices and not fight against them.

Author
Senko Rašić
We’re small, experienced and passionate team of web developers, doing custom app development and web consulting.