Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
216 changes: 126 additions & 90 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,135 +1,171 @@
|pythonapp|
Making React a First-Class Citizen in Django CMS with React Router Integration
===============================================================================

#####################
django CMS quickstart
#####################
Introduction
------------

- A dockerised django CMS project intended to be run locally in Docker on your own machine or on a Docker-based cloud, such as `Divio <https://www.divio.com/>`_
- This version uses Python 3.11 and the most up-to-date versions of Django 4.2, and django CMS 4.1.0
- This project is endorsed by the `django CMS Association <https://www.django-cms.org/en/about-us/>`_. That means that it is officially accepted by the dCA as being in line with our roadmap vision and development/plugin policy. Join us on `Slack <https://www.django-cms.org/slack/>`_ for more information or questions.
- The documentation for django CMS can be found here: https://docs.django-cms.org/
Django CMS is a powerful content management system that excels at structured, editorial content.
However, modern frontend experiences often demand the flexibility and interactivity of React.

Installation
############
In this post, we'll walk through how React — along with React Router — can be integrated as
first-class citizens in a Django CMS project, so that your editors and frontend engineers
can both thrive.

Requirements
============
Why Integrate React with Django CMS
-----------------------------------

You need to have Docker installed on your system to run this project.
- Django CMS provides content structure, versioning, and editorial workflows.
- React enables interactive, dynamic UIs with modern developer ergonomics.
- Common use cases:

- `Install Docker <https://docs.docker.com/engine/install/>`_ here.
- If you have not used docker in the past, please read this
`introduction on docker <https://docs.docker.com/get-started/>`_ here.
- Embedding a dashboard or widget inside CMS-managed pages.
- Creating fully dynamic web apps that live at certain CMS-defined routes.
- Building reusable React-based plugins inside Django CMS placeholders.

Local Setup
===========
Approach Overview
-----------------

.. inclusion-marker-do-not-remove
There are two major strategies:

.. code-block:: bash
- **SPA-in-CMS:** Let Django CMS render the base HTML layout and inject React into a placeholder.
- **CMS-in-SPA:** Use Django CMS as a headless backend and build everything with React.

git clone git@github.com:django-cms/django-cms-quickstart.git
cd django-cms-quickstart
docker compose build web
docker compose up -d database_default
docker compose run --rm web python manage.py migrate
docker compose run --rm web python manage.py createsuperuser
docker compose up -d
In this guide, we'll use the **SPA-in-CMS** approach, where React is bootstrapped inside
a Django CMS placeholder and React Router manages the internal routing.

Then open http://django-cms-quickstart.127.0.0.1.nip.io:8000 (or just http://127.0.0.1:8000) in your browser.
Project Setup
-------------

You can stop the server with ``docker compose stop`` without destroying the containers and restart it with
``docker compose start``.
1. Setup Django CMS (you can use `djangocms-installer` or your custom setup).
2. Create a React app:

With ``docker compose down`` the containers are deleted, but the database content is still preserved in the named
volume ``django-cms-quickstart_postgres-data`` and the media files are stored in the file system in ``data/media``.
Then you can update the project e. g. by changing the requirements and settings. Finally you can rebuild the web image
and start the server again:
- With `create-react-app`, Vite, or Webpack.
3. Integrate using either:

.. code-block:: bash
- `django-webpack-loader` (Webpack),
- or `django-vite`.

docker compose build web
docker compose up -d
Serving React from Django CMS
-----------------------------

- Create a Django CMS plugin that renders a `<div id="react-root"></div>` in a placeholder.
- This div acts as the mounting point for the React app.
- Your CMS template might look like:

Note: Since Compose V2, ``docker-compose`` is now included inside docker. For more information, checkout the
`Compose V2 <https://docs.docker.com/compose/cli-command/>`_ Documentation.
.. code-block:: html

.. inclusion-end-marker-do-not-remove
{% load render_placeholder %}
<html>
<body>
{% render_placeholder "main" %}
<script src="{% render_bundle 'main' %}"></script>
</body>
</html>

Customising the project
#######################
- You can also pass page or context data from the backend to React via `data-*` attributes or global JS variables.

This project is ready-to-go without making any changes at all, but also gives you some options.
React Router Configuration
--------------------------

As-is, it will include a number of useful django CMS plugins and Bootstrap 4 for the frontend. You don't have to use
these; they're optional. If you don't want to use them, read through the ``settings.py`` and ``requirements.txt`` files
to see sections that can be removed - in each case, the section is noted with a comment containing the word 'optional'.
- Wrap your React app with `<BrowserRouter>` or `<HashRouter>`.
- Configure a base path if the React app lives under a CMS-defined URL like `/app/`.
- Example:

Options are also available for using Postgres/MySQL, uWSGI/Gunicorn/Guvicorn, etc.
.. code-block:: jsx

Updating requirements
=====================
import { BrowserRouter, Routes, Route } from 'react-router-dom';

The project uses a django best practise two step approach, freezing all dependencies with pip-tools. Here is how to update requirements:
const App = () => (
<BrowserRouter basename="/app">
<Routes>
<Route path="/" element={<Home />} />
<Route path="profile" element={<Profile />} />
</Routes>
</BrowserRouter>
);

1. Change ``requirements.in`` according to your needs. There is no need to pin the package versions here unless you have a good reason (i.e. known incompatibilities)
2. Run ``docker compose run --rm web pip-compile requirements.in >> requirements.txt``
3. ``requirements.txt`` should now have changed
4. Rebuild the container ``docker compose build web`` and restart ``docker compose up -d``
Handling Routing Conflicts
--------------------------

Features
########
- Prevent Django from trying to resolve React's client-side routes.
- Add a CMS page with the URL `/app/` and insert your React plugin there.
- Any sub-routes like `/app/profile` will be handled by React Router.

Static Files with Whitenoise
============================
Advanced Considerations
-----------------------

- This quickstart demo has a cloud-ready static files setup via django-whitenoise.
- In the containerized cloud the application is not served by a web server like nginx but directly through uwsgi. django-whitenoise is the glue that's needed to serve static files in your application directly through uwsgi.
- See the django-whitenoise settings in settings.py and the ``quickstart/templates/whitenoise-static-files-demo.html`` demo page template that serves a static file.
- **SEO/SSR**: React apps are client-side rendered; for SEO-heavy use cases, consider SSR or pre-rendering.
- **i18n**: Pass `language_code` from Django CMS to React, and use libraries like `react-i18next`.
- **Context sync**: Provide CMS context to React via props, global config, or context providers.

Env variables
=============
Example Configuration Snippets
------------------------------

- By default, Docker injects the env vars defined in ``.env-local`` into the quickstart project.
- If you want to access the PostgreSQL database from the host system, set ``DB_PORT`` to the desired port number.
5432 is the standard port number. If you run PosgreSQL on your host system, you may want to set another port number.
If this variable is empty (the default), the PosgreSQL instance in the container is only reachable within docker, but
not from outside.
- **Webpack:**

Contribution
############
.. code-block:: js

Here is the official django CMS repository:
`https://github.com/django-cms/django-cms-quickstart/ <https://github.com/django-cms/django-cms-quickstart/>`_.
// webpack.config.js
output: {
publicPath: '/static/webpack_bundles/',
}

- **settings.py:**

Deployment
##########
.. code-block:: python

Note that this is just a demo project to get you started. It is designed to be run locally through docker. If you want a full production ready site with all the bells
and whistles we recommend you have a look at https://github.com/django-cms/djangocms-template instead.
INSTALLED_APPS += ['webpack_loader']
WEBPACK_LOADER = {
'DEFAULT': {
'BUNDLE_DIR_NAME': 'webpack_bundles/',
'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json'),
}
}

Some deployment hints:
- **CMS Template:**

- To deploy this project in testing mode (recommended) set the environment variable ``DEBUG`` to ``True`` in your hosting environment.
- Be aware that if ``DEBUG`` is false, django requires you to whitelist the domain. Set the env var ``DOMAIN`` to the host, i.e. ``www.domain.com`` or ``*.domain.com``.
- You can set the env var ``DEFAULT_STORAGE_DSN`` to something meaningful (i.e. for s3 file storage)
.. code-block:: html

Deployment Commands
===================
<div id="react-root"></div>

Configure your hosting environment to run the following commands on every deployment:
- **React App Entry:**

- ``./manage.py migrate``
.. code-block:: js

import ReactDOM from 'react-dom/client';
import App from './App';

Divio Deployment
================
const root = document.getElementById('react-root');
ReactDOM.createRoot(root).render(<App />);

divio.com is a cloud hosting platform optimized for django web applications. It's the quickest way to deploy this
project. Here is a `video tutorial <https://www.youtube.com/watch?v=O2g5Wfoyp7Q>`_ and a
`description of the deployment steps <https://github.com/django-cms/djangocms-template/blob/mco-standalone/docs/deployment-divio.md#divio-project-setup>`_ that are mostly applicable for this quickstart project.
Deployment Tips
---------------

- Run `npm run build` (or Vite equivalent).
- Collect static files via `collectstatic`.
- Optionally serve assets via CDN.
- Avoid client/server routing conflicts by keeping React confined under predictable base paths.

.. |pythonapp| image:: https://github.com/django-cms/django-cms-quickstart/workflows/Python%20application/badge.svg?branch=support/cms-4.1.x
Conclusion
----------

By carefully integrating React into Django CMS via placeholders and using React Router for
client-side navigation, you can build rich, dynamic UIs within an editorially friendly platform.

This hybrid setup lets you enjoy the best of both worlds — clean backend content structure
and dynamic, reactive frontends.

Optional Appendix
-----------------

- Example repo link (if any)
- Troubleshooting:

- Missing static files?
- Routing conflicts?
- React Router not picking up URL paths?

- Future ideas:

- Use of Next.js or RSC (React Server Components).
- CMS-driven metadata injection for SSR.
Loading