Skip to main content

Run a Django backend (Django ORM, Django Admin) alongside a Reflex app.

Project description

reflex-django

Keep Django. Get a reactive UI in Python. One process, shared cookies, native Reflex dev.

PyPI Python Docs License

Documentation · GitHub · PyPI


What is it?

You love Django — the ORM, the admin, migrations, the way it just works. You also want a modern, reactive UI written in Python, not React.

reflex-django runs Django and Reflex as one ASGI app on one port. Reflex config lives in settings.py. Pages live in views.py. The SPA catch-all is automatic. The Django session you got from /admin/login/ is the same session your Reflex button handlers see.

  • One process — production on one port; dev runs Vite (:3000) + backend (:8000) via run_reflex. No CORS, no token bridge.
  • Same cookies — log in once at /admin/, every Reflex event sees self.request.user.
  • Same middleware — your full settings.MIDDLEWARE chain runs on every Reflex event.
  • One commandpython manage.py run_reflex.

Minimal setup

Install:

uv add django reflex reflex-django

config/settings.py:

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "reflex_django",
    "shop",
]

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
    "reflex_django.streaming_middleware.AsyncStreamingMiddleware",
]

REFLEX_DJANGO_RX_CONFIG = {
    "app_name": "shop",
    "frontend_port": 3000,
    "backend_port": 8000,
}

config/urls.py:

import shop.views  # noqa: F401 — register @page decorators at import time

from django.contrib import admin
from django.urls import path

urlpatterns = [path("admin/", admin.site.urls)]
# catch-all: automatic (REFLEX_DJANGO_AUTO_MOUNT=True)

config/asgi.py:

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
from reflex_django.asgi_entry import application  # noqa: E402,F401

shop/views.py:

import reflex as rx
from reflex_django.pages.decorators import page
from reflex_django.states import AppState


class HomeState(AppState):
    @rx.event
    async def on_load(self):
        user = self.request.user
        self.greeting = (
            f"Hi, {user.get_username()}!"
            if user.is_authenticated
            else "Hello, guest. Log in at /admin/."
        )


@page(route="/", title="Home", on_load=HomeState.on_load)
def index() -> rx.Component:
    return rx.vstack(
        rx.heading("My Shop"),
        rx.text(HomeState.greeting),
    )

Run:

python manage.py migrate
python manage.py run_reflex

run_reflex starts two dev servers: Vite on :3000 (SPA + hot reload) and Django/Reflex on :8000 (admin, API, /_event).

Open http://localhost:3000/ for your Reflex UI. Admin at http://localhost:8000/admin/ (Vite proxies admin/API paths to :8000).

Optional: python manage.py run_reflex --single-port to browse only http://localhost:8000/.

That's it.


Why it exists

Reflex sends UI events over a WebSocket on /_event. Django middleware doesn't run on WebSockets. So request.user, sessions, messages, and CSRF aren't available inside @rx.event handlers by default — and the SPA usually wants its own port, which breaks cookie sharing.

reflex-django builds a synthetic HttpRequest for every event, runs your full settings.MIDDLEWARE chain on it, and binds self.request, self.user, self.session, self.messages, self.csrf_token onto your AppState handler. One process. One port. Same auth as your admin.

Full explanation: Why reflex-django exists.


Three knobs

Knob Where What you configure
Settings settings.py INSTALLED_APPS, MIDDLEWARE, REFLEX_DJANGO_RX_CONFIG (app_name, ports, redis_url, …)
App {app}/views.py @page pages and AppState subclasses (from reflex_django import app for add_page)
URLs urls.py Django routes + import shop.views to register pages; catch-all is automatic

No rxconfig.py. No {app}/{app}.py. No required reflex_mount() line. Call reflex_mount() only for URL overrides (mount_prefix, explicit django_prefix).

Full map: The three knobs.


Versions

Version
Python 3.12+
Django 6.0+
Reflex 0.9.2+

Documentation

The full docs walk you through the why, the how, and every knob:

Site: https://web7ai.github.io/reflex-django/


Common commands

python manage.py run_reflex            # dev server (auto-rebuild + watch)
python manage.py run_reflex --skip-rebuild   # faster reloads for pure Python edits
python manage.py export_reflex         # build the SPA bundle (for CI / deploy)
python manage.py migrate
python manage.py createsuperuser

Author: Mohannad Irshedat · GitHub · Docs

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

reflex_django-0.5.0.tar.gz (246.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

reflex_django-0.5.0-py3-none-any.whl (223.3 kB view details)

Uploaded Python 3

File details

Details for the file reflex_django-0.5.0.tar.gz.

File metadata

  • Download URL: reflex_django-0.5.0.tar.gz
  • Upload date:
  • Size: 246.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.0 {"installer":{"name":"uv","version":"0.11.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for reflex_django-0.5.0.tar.gz
Algorithm Hash digest
SHA256 5f7906d8066fe53e0415963cb1cce9c73589021a82d90faa292107cc02ae5370
MD5 929b253279a92c85f338f0d942ff0e71
BLAKE2b-256 40b3b61ea8ce08616e9683336859cdff65a2ff81585a9ebf91d1e8e8fc36a1a1

See more details on using hashes here.

File details

Details for the file reflex_django-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: reflex_django-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 223.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.0 {"installer":{"name":"uv","version":"0.11.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for reflex_django-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7b56f27dc57d52d46d8159da20dfc0e14a3101b9651364cdd4d03ff53c40b076
MD5 7485646b1a2b98bf5a5a4d856e9aa4cb
BLAKE2b-256 bdf4e78629475e43ce4cad7a35db93a6d01334bc4e20cbb76ec7a011f5ae1946

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page