|
1 |
| -|pythonapp| |
| 1 | +Making React a First-Class Citizen in Django CMS with React Router Integration |
| 2 | +=============================================================================== |
2 | 3 |
|
3 |
| -##################### |
4 |
| -django CMS quickstart |
5 |
| -##################### |
| 4 | +Introduction |
| 5 | +------------ |
6 | 6 |
|
7 |
| -- 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/>`_ |
8 |
| -- This version uses Python 3.11 and the most up-to-date versions of Django 4.2, and django CMS 4.1.0 |
9 |
| -- 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. |
10 |
| -- The documentation for django CMS can be found here: https://docs.django-cms.org/ |
| 7 | +Django CMS is a powerful content management system that excels at structured, editorial content. |
| 8 | +However, modern frontend experiences often demand the flexibility and interactivity of React. |
11 | 9 |
|
12 |
| -Installation |
13 |
| -############ |
| 10 | +In this post, we'll walk through how React — along with React Router — can be integrated as |
| 11 | +first-class citizens in a Django CMS project, so that your editors and frontend engineers |
| 12 | +can both thrive. |
14 | 13 |
|
15 |
| -Requirements |
16 |
| -============ |
| 14 | +Why Integrate React with Django CMS |
| 15 | +----------------------------------- |
17 | 16 |
|
18 |
| -You need to have Docker installed on your system to run this project. |
| 17 | +- Django CMS provides content structure, versioning, and editorial workflows. |
| 18 | +- React enables interactive, dynamic UIs with modern developer ergonomics. |
| 19 | +- Common use cases: |
19 | 20 |
|
20 |
| -- `Install Docker <https://docs.docker.com/engine/install/>`_ here. |
21 |
| -- If you have not used docker in the past, please read this |
22 |
| - `introduction on docker <https://docs.docker.com/get-started/>`_ here. |
| 21 | + - Embedding a dashboard or widget inside CMS-managed pages. |
| 22 | + - Creating fully dynamic web apps that live at certain CMS-defined routes. |
| 23 | + - Building reusable React-based plugins inside Django CMS placeholders. |
23 | 24 |
|
24 |
| -Local Setup |
25 |
| -=========== |
| 25 | +Approach Overview |
| 26 | +----------------- |
26 | 27 |
|
27 |
| -.. inclusion-marker-do-not-remove |
| 28 | +There are two major strategies: |
28 | 29 |
|
29 |
| -.. code-block:: bash |
| 30 | +- **SPA-in-CMS:** Let Django CMS render the base HTML layout and inject React into a placeholder. |
| 31 | +- **CMS-in-SPA:** Use Django CMS as a headless backend and build everything with React. |
30 | 32 |
|
31 |
| - git clone git@github.com:django-cms/django-cms-quickstart.git |
32 |
| - cd django-cms-quickstart |
33 |
| - docker compose build web |
34 |
| - docker compose up -d database_default |
35 |
| - docker compose run --rm web python manage.py migrate |
36 |
| - docker compose run --rm web python manage.py createsuperuser |
37 |
| - docker compose up -d |
| 33 | +In this guide, we'll use the **SPA-in-CMS** approach, where React is bootstrapped inside |
| 34 | +a Django CMS placeholder and React Router manages the internal routing. |
38 | 35 |
|
39 |
| -Then open http://django-cms-quickstart.127.0.0.1.nip.io:8000 (or just http://127.0.0.1:8000) in your browser. |
| 36 | +Project Setup |
| 37 | +------------- |
40 | 38 |
|
41 |
| -You can stop the server with ``docker compose stop`` without destroying the containers and restart it with |
42 |
| -``docker compose start``. |
| 39 | +1. Setup Django CMS (you can use `djangocms-installer` or your custom setup). |
| 40 | +2. Create a React app: |
43 | 41 |
|
44 |
| -With ``docker compose down`` the containers are deleted, but the database content is still preserved in the named |
45 |
| -volume ``django-cms-quickstart_postgres-data`` and the media files are stored in the file system in ``data/media``. |
46 |
| -Then you can update the project e. g. by changing the requirements and settings. Finally you can rebuild the web image |
47 |
| -and start the server again: |
| 42 | + - With `create-react-app`, Vite, or Webpack. |
| 43 | +3. Integrate using either: |
48 | 44 |
|
49 |
| -.. code-block:: bash |
| 45 | + - `django-webpack-loader` (Webpack), |
| 46 | + - or `django-vite`. |
50 | 47 |
|
51 |
| - docker compose build web |
52 |
| - docker compose up -d |
| 48 | +Serving React from Django CMS |
| 49 | +----------------------------- |
53 | 50 |
|
| 51 | +- Create a Django CMS plugin that renders a `<div id="react-root"></div>` in a placeholder. |
| 52 | +- This div acts as the mounting point for the React app. |
| 53 | +- Your CMS template might look like: |
54 | 54 |
|
55 |
| -Note: Since Compose V2, ``docker-compose`` is now included inside docker. For more information, checkout the |
56 |
| -`Compose V2 <https://docs.docker.com/compose/cli-command/>`_ Documentation. |
| 55 | + .. code-block:: html |
57 | 56 |
|
58 |
| -.. inclusion-end-marker-do-not-remove |
| 57 | + {% load render_placeholder %} |
| 58 | + <html> |
| 59 | + <body> |
| 60 | + {% render_placeholder "main" %} |
| 61 | + <script src="{% render_bundle 'main' %}"></script> |
| 62 | + </body> |
| 63 | + </html> |
59 | 64 |
|
60 |
| -Customising the project |
61 |
| -####################### |
| 65 | +- You can also pass page or context data from the backend to React via `data-*` attributes or global JS variables. |
62 | 66 |
|
63 |
| -This project is ready-to-go without making any changes at all, but also gives you some options. |
| 67 | +React Router Configuration |
| 68 | +-------------------------- |
64 | 69 |
|
65 |
| -As-is, it will include a number of useful django CMS plugins and Bootstrap 4 for the frontend. You don't have to use |
66 |
| -these; they're optional. If you don't want to use them, read through the ``settings.py`` and ``requirements.txt`` files |
67 |
| -to see sections that can be removed - in each case, the section is noted with a comment containing the word 'optional'. |
| 70 | +- Wrap your React app with `<BrowserRouter>` or `<HashRouter>`. |
| 71 | +- Configure a base path if the React app lives under a CMS-defined URL like `/app/`. |
| 72 | +- Example: |
68 | 73 |
|
69 |
| -Options are also available for using Postgres/MySQL, uWSGI/Gunicorn/Guvicorn, etc. |
| 74 | + .. code-block:: jsx |
70 | 75 |
|
71 |
| -Updating requirements |
72 |
| -===================== |
| 76 | + import { BrowserRouter, Routes, Route } from 'react-router-dom'; |
73 | 77 |
|
74 |
| -The project uses a django best practise two step approach, freezing all dependencies with pip-tools. Here is how to update requirements: |
| 78 | + const App = () => ( |
| 79 | + <BrowserRouter basename="/app"> |
| 80 | + <Routes> |
| 81 | + <Route path="/" element={<Home />} /> |
| 82 | + <Route path="profile" element={<Profile />} /> |
| 83 | + </Routes> |
| 84 | + </BrowserRouter> |
| 85 | + ); |
75 | 86 |
|
76 |
| -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) |
77 |
| -2. Run ``docker compose run --rm web pip-compile requirements.in >> requirements.txt`` |
78 |
| -3. ``requirements.txt`` should now have changed |
79 |
| -4. Rebuild the container ``docker compose build web`` and restart ``docker compose up -d`` |
| 87 | +Handling Routing Conflicts |
| 88 | +-------------------------- |
80 | 89 |
|
81 |
| -Features |
82 |
| -######## |
| 90 | +- Prevent Django from trying to resolve React's client-side routes. |
| 91 | +- Add a CMS page with the URL `/app/` and insert your React plugin there. |
| 92 | +- Any sub-routes like `/app/profile` will be handled by React Router. |
83 | 93 |
|
84 |
| -Static Files with Whitenoise |
85 |
| -============================ |
| 94 | +Advanced Considerations |
| 95 | +----------------------- |
86 | 96 |
|
87 |
| -- This quickstart demo has a cloud-ready static files setup via django-whitenoise. |
88 |
| -- 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. |
89 |
| -- 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. |
| 97 | +- **SEO/SSR**: React apps are client-side rendered; for SEO-heavy use cases, consider SSR or pre-rendering. |
| 98 | +- **i18n**: Pass `language_code` from Django CMS to React, and use libraries like `react-i18next`. |
| 99 | +- **Context sync**: Provide CMS context to React via props, global config, or context providers. |
90 | 100 |
|
91 |
| -Env variables |
92 |
| -============= |
| 101 | +Example Configuration Snippets |
| 102 | +------------------------------ |
93 | 103 |
|
94 |
| -- By default, Docker injects the env vars defined in ``.env-local`` into the quickstart project. |
95 |
| -- If you want to access the PostgreSQL database from the host system, set ``DB_PORT`` to the desired port number. |
96 |
| - 5432 is the standard port number. If you run PosgreSQL on your host system, you may want to set another port number. |
97 |
| - If this variable is empty (the default), the PosgreSQL instance in the container is only reachable within docker, but |
98 |
| - not from outside. |
| 104 | +- **Webpack:** |
99 | 105 |
|
100 |
| -Contribution |
101 |
| -############ |
| 106 | + .. code-block:: js |
102 | 107 |
|
103 |
| -Here is the official django CMS repository: |
104 |
| -`https://github.com/django-cms/django-cms-quickstart/ <https://github.com/django-cms/django-cms-quickstart/>`_. |
| 108 | + // webpack.config.js |
| 109 | + output: { |
| 110 | + publicPath: '/static/webpack_bundles/', |
| 111 | + } |
105 | 112 |
|
| 113 | +- **settings.py:** |
106 | 114 |
|
107 |
| -Deployment |
108 |
| -########## |
| 115 | + .. code-block:: python |
109 | 116 |
|
110 |
| -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 |
111 |
| -and whistles we recommend you have a look at https://github.com/django-cms/djangocms-template instead. |
| 117 | + INSTALLED_APPS += ['webpack_loader'] |
| 118 | + WEBPACK_LOADER = { |
| 119 | + 'DEFAULT': { |
| 120 | + 'BUNDLE_DIR_NAME': 'webpack_bundles/', |
| 121 | + 'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json'), |
| 122 | + } |
| 123 | + } |
112 | 124 |
|
113 |
| -Some deployment hints: |
| 125 | +- **CMS Template:** |
114 | 126 |
|
115 |
| -- To deploy this project in testing mode (recommended) set the environment variable ``DEBUG`` to ``True`` in your hosting environment. |
116 |
| -- 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``. |
117 |
| -- You can set the env var ``DEFAULT_STORAGE_DSN`` to something meaningful (i.e. for s3 file storage) |
| 127 | + .. code-block:: html |
118 | 128 |
|
119 |
| -Deployment Commands |
120 |
| -=================== |
| 129 | + <div id="react-root"></div> |
121 | 130 |
|
122 |
| -Configure your hosting environment to run the following commands on every deployment: |
| 131 | +- **React App Entry:** |
123 | 132 |
|
124 |
| -- ``./manage.py migrate`` |
| 133 | + .. code-block:: js |
125 | 134 |
|
| 135 | + import ReactDOM from 'react-dom/client'; |
| 136 | + import App from './App'; |
126 | 137 |
|
127 |
| -Divio Deployment |
128 |
| -================ |
| 138 | + const root = document.getElementById('react-root'); |
| 139 | + ReactDOM.createRoot(root).render(<App />); |
129 | 140 |
|
130 |
| -divio.com is a cloud hosting platform optimized for django web applications. It's the quickest way to deploy this |
131 |
| -project. Here is a `video tutorial <https://www.youtube.com/watch?v=O2g5Wfoyp7Q>`_ and a |
132 |
| -`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. |
| 141 | +Deployment Tips |
| 142 | +--------------- |
133 | 143 |
|
| 144 | +- Run `npm run build` (or Vite equivalent). |
| 145 | +- Collect static files via `collectstatic`. |
| 146 | +- Optionally serve assets via CDN. |
| 147 | +- Avoid client/server routing conflicts by keeping React confined under predictable base paths. |
134 | 148 |
|
135 |
| -.. |pythonapp| image:: https://github.com/django-cms/django-cms-quickstart/workflows/Python%20application/badge.svg?branch=support/cms-4.1.x |
| 149 | +Conclusion |
| 150 | +---------- |
| 151 | + |
| 152 | +By carefully integrating React into Django CMS via placeholders and using React Router for |
| 153 | +client-side navigation, you can build rich, dynamic UIs within an editorially friendly platform. |
| 154 | + |
| 155 | +This hybrid setup lets you enjoy the best of both worlds — clean backend content structure |
| 156 | +and dynamic, reactive frontends. |
| 157 | + |
| 158 | +Optional Appendix |
| 159 | +----------------- |
| 160 | + |
| 161 | +- Example repo link (if any) |
| 162 | +- Troubleshooting: |
| 163 | + |
| 164 | + - Missing static files? |
| 165 | + - Routing conflicts? |
| 166 | + - React Router not picking up URL paths? |
| 167 | + |
| 168 | +- Future ideas: |
| 169 | + |
| 170 | + - Use of Next.js or RSC (React Server Components). |
| 171 | + - CMS-driven metadata injection for SSR. |
0 commit comments