# reflex-django — LLM and agent guide

This file orients coding agents and LLMs: how reflex-django fits Reflex + Django, what to import, how to configure it safely, and common mistakes. For tutorials and longer examples, read `README.md` in this directory.

---

## Metadata

| Item | Value |
|------|--------|
| Package | `reflex-django` (import: `reflex_django`) |
| Version | 3.0+ |
| Purpose | Run Django (ORM, admin, sessions, auth) alongside Reflex. **Dev:** `manage.py run_reflex` → Vite + Reflex backend with Django mounted in-process via `make_dispatcher`. **Production:** plain `get_asgi_application()` + `reflex_mount()`. |
| Python | `>=3.12,<4.0` |
| Django | `>=6.0,<7.0` |
| Reflex | `>=0.9.2,<1.0` |
| License | Apache-2.0 (see `LICENSE`) |

---

## What it is / what it is not

**Is:** A Django-first integration (default) that loads Reflex config from `settings.py` (`RX_CONFIG`), **or** a Reflex-first path via `ReflexDjangoPlugin` in on-disk `rxconfig.py`. Both mount Django HTTP routes inside the Reflex dev backend via `make_dispatcher` on `app.api_transformer`, and install **Reflex event middleware** (`DjangoEventBridge`).

**Is not:** A single merged URL router for production. Production Django uses normal `urlpatterns` + `reflex_mount()`. Reflex `/_event` traffic is not a Django view; Django HTTP middleware runs for events only through the **event bridge**.

---

## Agent setup checklist

Do these in order:

1. Add dependencies: `uv add reflex reflex-django` (or equivalent).
2. Django project with `manage.py`, `config/settings.py`, `config/urls.py`, `config/asgi.py`.
3. **`config/asgi.py`:** `application = get_asgi_application()` (not `reflex_django.asgi.entry`).
4. **`settings.py`:** `RX_CONFIG`, `INSTALLED_APPS` including `reflex_django`, Django contrib apps as needed.
5. **`urls.py`:** import page modules for `@page` registration; add `reflex_mount()` catch-all; optional `admin_urlpatterns("/admin")`.
6. **Dev (Django-first):** `python manage.py run_reflex` — browse `:3000`; Vite proxies to Reflex backend (`:8000` default) where Django admin/API are mounted in-process.
7. **Dev (Reflex-first):** Add `ReflexDjangoPlugin(config={...})` to `rxconfig.py` `plugins`, then `reflex run`. See `docs/getting-started/existing_reflex_project_plugin.md`.
8. **Optional split dev:** Terminal 1 `runserver`, Terminal 2 `run_reflex` with `RX_PROXY_SERVER = "http://127.0.0.1:8000"`.

See `docs/getting-started/local_development.md`.

---

## Architecture (compact, v3)

```text
Dev — browse :3000
Browser → Vite (:3000) → Reflex backend (:8000, api_transformer / make_dispatcher)
                              ├── /admin, /api → Django ASGI (in-process)
                              ├── /, /about    → Reflex SPA
                              └── /_event      → Reflex inner ASGI → DjangoEventBridge → @rx.event

Production
Browser → edge proxy → Django ASGI (admin, API, SPA shell via reflex_mount)
                    → Reflex backend for /_event, /_upload
```

- **HTTP bridge (dev):** `make_dispatcher` in `src/reflex_django/asgi/app.py` (import: `from reflex_django.asgi.app import make_dispatcher`).
- **Event bridge:** `DjangoEventBridge` in `src/reflex_django/bridge/event/`; tiers in `bridge/tier.py`, cache in `bridge/cache.py`. See `docs/operations/scaling.md`.
- **Removed in v3:** `setup/plugin.py` (restored in v3.1+ as `reflex_django.plugins`), `RX_AUTO_DISCOVER_PAGES`, `RX_LOGIN_URL`, `RX_I18N_EVENT_BRIDGE`, `reflex_page` alias, `reflex_mount(app_name=...)`, top-level `make_dispatcher`.
- **Reflex-first (v3.1+):** `ReflexDjangoPlugin` / `RXDJANGOPLUGIN` in `rxconfig.py` — use `reflex run`; Django-first remains default without the plugin.

---

## Public API (package `reflex_django`)

These names match `__all__` in `src/reflex_django/__init__.py`. Many are **lazy-loaded** (see next section).

| Area | Symbols |
|------|---------|
| Django init | `configure_django` |
| ASGI | `build_django_asgi`; `make_dispatcher` from `reflex_django.asgi.app` only |
| Per-event context | **`request`** (`request.user`, `request.session`, `request.GET`, `request.headers`), `current_request`, `current_user`, `current_session`, `current_language`, `begin_event_request`, `end_event_request` |
| Event middleware | `DjangoEventBridge`, `resolve_bridge_tier`, `invalidate_event_cache` |
| Reflex state helpers | `AppState`, `ModelState`, `DjangoUserState`, `DjangoI18nState` |
| Per-event context | `current_user`, `current_session`, `current_request`, `current_messages`, `current_language`, `current_csrf_token` |
| Auth shortcuts | `require_login_user`, `auser_has_perm`, `ReflexDjangoAuthError` (`reflex_django.auth.shortcuts`) |
| Auth decorators | `login_required`, `permission_required` (pages and event handlers; `reflex_django.auth.decorators`) |
| AppState auth API | `self.user`, `self.session`, `login`, `logout`, `has_perm`, `has_group`, `on_auth_failed`, `on_permission_denied` on `AppState` / `DjangoUserState` |
| Canned auth UI | `add_auth_pages`, `register_login_page`, `register_register_page`, `register_password_reset_page`, `register_password_reset_confirm_page`, `LoginPage`, `RegisterPage`, `PasswordResetPage`, `PasswordResetConfirmPage`, `autoload`, `DjangoAuthState`, `get_auth_settings`, `AuthSettings`, `auth_pages`, `auth_routes` (subpackage `reflex_django.auth`) |
| User JSON snapshot | `user_snapshot` (dict for display, processors, tests—not authorization) |
| ORM helper | `Model` (abstract Django model base + Reflex serializer) |
| Model serializers | `ReflexDjangoModelSerializer` (`Meta.fields` / `exclude` / `read_only_fields`, `.data`, `.adata`, queryset `many=True`) |
| Declarative model CRUD state | `ModelCRUDView` / `ModelState`, `ModelListView` (`reflex_django.state`; see **ModelCRUDView** section below) |
| Admin | `register_admin` |
| Session / cookies (JS helpers) | `session_cookie_set_js`, `session_cookie_clear_js`, `session_cookie_name_and_suffix` |
| CLI (programmatic) | `django_cli` |

## Request proxy in event handlers

**Import:** `from reflex_django import request` (lazy on package root; **not** `reflex_django.state.request`)

Requires `DjangoEventBridge` / `install_event_bridge=True`.

```python
@rx.event
async def handler(self):
    request.user
    request.session
    request.GET.get("page")
    request.headers.get("cookie")
    request.path
    request.COOKIES
```

Populated from `event.router_data`: `pathname` (+ `?query`), `query` dict, `headers`, cookies. Outside an event: `request.user` → anonymous, `request.GET` → empty `QueryDict`.

**Never** put `request.user` in `rx.text()` / components (Django model is not a Reflex child). UI: `DjangoAuthState.username` / `AppState.username`. Logout / `@login_required` page shell: **`DjangoAuthState.is_authenticated`** (`@rx.var` → `current_user()`, not inherited snapshot). Handlers: `request.user.is_authenticated` or `request.username` (str).

**ModelState:** `self.request` during `dispatch` is `DjangoStateRequest` (adds context-processor keys). Module `request` is the raw `HttpRequest`.

---

**Submodule extras (not re-exported on the package root):** **`reflex_django.mixins`** exposes **`SessionAuthConfig` / `session_auth_mixin`** (Django session login/logout in Reflex events); see `README.md`. **`reflex_django.auth`** provides canned pages as **`BaseAuthPage`** subclasses (**`LoginPage`**, **`RegisterPage`**, …). Override hook methods (`heading_text`, `form_fields`, …), **`state_cls`**, or **`render()`**; copy via **`MESSAGES`** in **`RX_AUTH`**. Register with **`app.add_page`**, **`register_*_page`** (uses **`default_on_load`**), or **`add_auth_pages(app)`**.

---

## Critical rule: lazy imports on `reflex_django`

Many public attributes are resolved via **PEP 562** `__getattr__` so submodules that touch the Django ORM, admin, or HTTP stack are not imported until **after** `django.setup()`-compatible initialization.

**Do:** Import `from reflex_django import …` in application code after Django settings load in normal `run_reflex` startup. Prefer the package root for documented names.

**Avoid:** Import patterns that pull Django models or heavy `reflex_django` submodules at **import time before** settings and `configure_django()` have run.

---

## Django settings (`RX_*` and related)

Consolidated from `src/reflex_django/setup/default_settings.py` and related modules:

| Setting | Meaning |
|---------|---------|
| `RX_AUTO_SETTINGS` | `True` in bundled defaults; library warns that you should use your own settings + stable `SECRET_KEY` for production. |
| `RX_AUTH` | Dict: `ENABLED`, `SIGNUP_ENABLED`, `PASSWORD_RESET_ENABLED`, `LOGIN_URL`, route URLs, redirects, `EMAIL_REQUIRED`, `PASSWORD_MIN_LENGTH`, `MESSAGES`. See `reflex_django.auth.settings`. |
| `EMAIL_BACKEND` / `DEFAULT_FROM_EMAIL` | Required for password-reset emails (console backend OK in dev). |
| `RX_SITE_ORIGIN` | Optional absolute origin for reset links when no request is bound. |
| `RX_USER_SNAPSHOT_INCLUDE_GROUPS` | When `True`, user snapshots / `DjangoUserState` may include group names. |
| `RX_AUTH_AUTO_SYNC` | When `True` (default), `DjangoEventBridge` refreshes `AppState` auth snapshot vars on every event. |
| `RX_PAGE_PACKAGES` | Explicit page module paths. When empty, compile imports `{RX_CONFIG["app_name"]}.views` only. Import modules in `urls.py` at startup. |
| `RX_DATABASE_URL` | Optional env override for DB URL when using defaults (`default_settings._resolve_db_url`). |
| `RX_CONFIG` | Dict of `rx.Config` overrides: `frontend_port`, `backend_port`, `redis_url`, `frontend_packages`, CORS, etc. |
| `RX_PROXY_SERVER` | Optional. When set, Vite proxies Django URL prefixes to separate `runserver`. When unset, Django runs in-process on Reflex backend. |
| `RX_PLUGINS` | List of Reflex plugin dotted paths or instances. |
| `RX_EVENT_BRIDGE_MODE` | `"full"` (default), `"smart"`, or `"none"`. Tiered middleware on Reflex events. |
| `RX_AUTH_ONLY_MIDDLEWARE` | Tuple of middleware for `"auth_only"` tier (default: session + auth). |
| `RX_EVENT_BRIDGE_RESOLVER` | Optional dotted callable `(handler_state_cls, event) -> tier`. Highest precedence. |
| `RX_EVENT_RESOLVE_URL` | When `True`, populate `request.resolver_match` on synthetic event requests. |
| `RX_EVENT_CACHE` / `TTL` / `KEY_PREFIX` | Django `CACHES` alias and TTL for bridge auth snapshot cache (`0` disables). |
| `RX_EVENT_METRICS` | When `True`, log bridge phase timings at DEBUG. |
| `RX_PERFORMANCE_PRESET` | `"lean"` disables default mirror/auth-sync toggles when still at library defaults. |

**Override precedence:** `RX_EVENT_BRIDGE_RESOLVER` → `State._rx_bridge` → `RX_EVENT_BRIDGE_MODE` → smart defaults. Use `_rx_bridge` (underscore) — public attrs become Reflex state vars. Full guide: `docs/operations/scaling.md`.

Default settings also honor env vars such as `RX_STATIC_URL`, `RX_STATIC_ROOT`, `RX_SECRET_KEY`, `RX_DEBUG`, `RX_ALLOWED_HOSTS`, `RX_URLCONF`. Database URL can fall back from Reflex config `db_url` to a local SQLite file.

---

## Security and best practices

1. **Authorize on the server inside event handlers** using `self.user` / `current_user()`, `require_login_user()`, `await self.has_perm(...)`, or `await auser_has_perm(user, "app.codename")`. Never trust snapshot fields alone for permission checks—they are a **UI snapshot** synchronized to the client.
2. Use **`@login_required`** and **`@permission_required`** on event handlers to redirect anonymous or unauthorized users.
3. **`user_snapshot(user)`** (`from reflex_django import user_snapshot`) is for display, logging, or custom serializers—not a substitute for live `User` checks on mutations.
4. Anything assigned to Reflex **`rx.State`** fields that sync to the browser must be **JSON-serializable**.
5. Prefer **`async def`** event handlers when calling Django’s async APIs (`aget_user` is already used in the bridge for `request.user`).

---

## AppState authentication bridge (agent reference)

**Import:** `from reflex_django.states import AppState`  
**Also:** `from reflex_django.auth import login_required, permission_required`

`AppState` subclasses `DjangoUserState` + `AuthBridgeMixin`. Use for dashboards, auth-aware features, and `ModelCRUDView`.

### Two layers

| Layer | API | Use |
|-------|-----|-----|
| Live (handlers) | **`self.request`**, **`self.request.user`**, `self.user`, `self.session` | Authorization, ORM scoping, `GET`/`path`/cookies |
| Snapshot (UI) | `is_authenticated`, `username`, `email`, `group_names`, … on **AppState** / **DjangoUserState** | `rx.cond`, bindings — **not** `self.request.user` in components |
| Live UI (canned auth) | **`DjangoAuthState.is_authenticated`** (`@rx.var`) | Sidebar logout, `@login_required` page gate — **not** for handler authorization |

### `self.request` (handlers)

- **`self.request`** → `DjangoStateRequest` (`.user`, `.GET`, `.path`, `.context`, processor keys).
- **`self.django_request`** → raw `HttpRequest`.
- **`ModelCRUDView.dispatch`** → `bind_request_context()` merges context processors onto `self.request`.
- Plain `rx.State` → `from reflex_django import request` instead.

Human docs: `docs/guides/authentication.md#accessing-the-django-request-on-appstate`.

### Handler examples

```python
class S(AppState):
    @rx.event
    async def action(self):
        if not self.request.user.is_authenticated:
            return rx.redirect("/login")
        tab = self.request.GET.get("tab", "home")
        self.session["theme"] = "dark"
        if await self.has_perm("app.change_model"):
            ...
        if await self.has_group("admins"):
            ...

    @rx.event
    async def sign_in(self):
        if not await self.login(username, password):
            return await self.on_auth_failed()
        await self.logout()  # clears server session + refreshes snapshot
```

### Decorators

```python
@rx.event
@login_required(login_url="/login")
async def private(self): ...

@rx.event
@permission_required("products.view_product", redirect="/login", on_denied=...)
async def catalog(self): ...
```

### Cookie sync after login/logout

Reflex events skip `SessionMiddleware`. After `login()` / `logout()`, call `_sync_session_cookie_then_nav` from `reflex_django.mixins.session_auth` so the browser `sessionid` matches the server row.

**Django `sessionid` vs Reflex `token`:** Django auth uses the **`sessionid` cookie** (session table + `request.user`). Reflex stores a separate per-tab UUID in **`sessionStorage` under key `token`** (`router.session.client_token`) for WebSocket/state identity—not login. Logout must clear cookies, `router_data` cookie mirrors, and client storage (`browser_auth_logout_clear_js`) or stale `token` can cause `/` ↔ `/login` loops. See `docs/guides/authentication.md#browser-storage-django-sessionid-vs-reflex-token-for-django-developers`.

### Settings

- `RX_AUTH_AUTO_SYNC` (default True): bridge calls `refresh_django_user_fields()` on each event for `AppState` instances.
- `RX_USER_SNAPSHOT_INCLUDE_GROUPS`: load `group_names` in snapshot.

Human docs: `docs/guides/authentication.md`.

---

## Reflex + Django ORM

- Optional abstract base **`Model`** (`src/reflex_django/django/model.py`): subclass for tables; run migrations through the CLI below. Importing `reflex_django.django.model` calls `configure_django()`.
- Registered **serializer** turns Django `Model` instances into JSON-friendly dicts (includes PK) for Reflex wire format.

---

## ModelState — reactive ORM state (preferred)

**Import:** `from reflex_django.states import ModelState`  
**Full doc:** `docs/guides/crud.md#modelstate`  
**Comparison (ModelState vs ModelCRUDView):** `docs/guides/crud.md#choosing`  
**Requires:** event bridge on; includes **`AppState`** (auth).

### Pattern (any Django model)

```python
class ProductState(ModelState):
    model = Product
    fields = ["name", "price", "is_active"]
    ordering = ("-created_at",)
# Generated: data, error, editing_id, field vars, load, save, refresh, filter, …
```

Auto-builds serializer from `model` + `fields` unless `serializer_class` / `Meta.serializer` is set. Invalid field names → `ImproperlyConfigured` at import.

### UI wiring

```python
rx.button("Save", on_click=ProductState.save)
rx.button("Edit", on_click=ProductState.load(row["id"]))
on_mount=ProductState.refresh
```

### Canonical API (stable names)

`load(pk)`, `save()`, `create()`, `delete(pk=None)`, `refresh()`, `filter(**kwargs)`, `clear_filter()`, `paginate(page=…, page_size=…)`, `cancel_edit()`, `get_row(pk)`.

`editing_id == -1` → create on save; `>= 0` → update. `filter(**kwargs)` sets `_queryset_filter` then refresh.

Legacy names (`save_{model}`, `start_edit`, `on_load_data`) still generated. `Meta.use_canonical_api = False` skips canonical handlers.

**UI:** `rx.cond(State.data.length() > 0, …)` — not `len(State.data)`. **`Meta.run_model_validation`** only (not a class-body var). **`paginate_by`** seeds `page_size`.

### User scope

```python
class NoteState(ModelState, UserScopedMixin):
    model = Note
    fields = ["title", "body"]
    scope_field = "user_id"
```

---

## ModelCRUDView — explicit serializer CRUD (legacy / advanced)

**Import:** `from reflex_django.states import AppState`; `from reflex_django.state import ModelCRUDView, ModelListView`  
**Note:** `ModelState` is **not** an alias; it extends `AppState` + `ModelCRUDView` with `model` + `fields` shorthand.  
**Comparison guide:** `docs/guides/crud.md#choosing`  
**Requires:** event bridge on; `@login_required` on most generated handlers by default.

### Pattern

```python
class MyState(AppState, ModelCRUDView):
    serializer_class = MySerializer
    paginate_by = 20                  # class attrs: best IDE autocomplete
    search_fields = ("title",)

    class Meta(ModelCRUDMeta):          # or inner Meta; inherit ModelCRUDMeta for hints
        list_var = "notes"
```

Import: `from reflex_django.state import ModelCRUDMeta`

Assembly (via `AppStateMeta`) declares vars + handlers unless the subclass already defines the same name in its class body.

### Default reactive vars (`ModelState`)

| Member | Role |
|--------|------|
| `data` | `list[dict]` rows (`Meta.list_var`, default `"data"`) |
| `error` | validation message (`Meta.error_var`, default `"error"`) |
| `search`, `total_count`, `page_count` | when search / pagination enabled |
| `editing_id` | `int`, `-1` = create mode, `>=0` = editing pk |
| `title`, `content`, … | flat editable state vars (not `form_*` prefixes) |
| `set_title`, … | `@rx.event` setters |
| `_load_data` | internal reload |
| `on_load_data` | page `on_load` target |
| `save_note` | create or update from flat vars + `editing_id` |
| `start_edit(item_id)` | populate vars, set `editing_id` |
| `delete_note(item_id)` | delete + refresh list |
| `cancel_edit` | `reset_state_fields()` |
| `reset_state_fields` | clear editable vars, `editing_id=-1`, bump `form_reset_key` |
| `bump_form_reset_key` | increment `form_reset_key` only (custom remount without full reset) |
| `form_reset_key` | int; bind to `rx.form(..., key=...)` — bumps on save reset, cancel, and `start_edit` |
| `save_{model}_form` | optional when `Meta.use_form_submit = True`; reads `form_data` then `dispatch(save)` |

Canonical handlers on `ModelState`: `load`, `save`, `create`, `delete`, `refresh`, `filter`, `paginate`, …

### `ModelCRUDView` list/search names (legacy explicit serializer)

Default `list_var` = plural of model (`notes`, `products`, …) → `notes_error`, `notes_search`, `on_load_notes`, etc. Override with `Meta.list_var` or use `ModelState` for generic `data` / `error` / `search`.

**List features (opt-in via Meta):**

| Meta | Injects |
|------|---------|
| `paginate_by = 20` | `page`, `page_size`, `total_count`, `page_count`, `next_page`, `prev_page`, `go_to_page`, `set_page_size` |
| `search_fields = ("title",)` | `search`, `set_search`, `clear_search` |
| `allow_dynamic_ordering = True` | `ordering`, `set_ordering` |

Default `paginate_by = None` → full list (no page vars). Hooks: `apply_search`, `paginate_queryset`, `get_ordering`, `on_page_change`.

### Event flow

```text
on_load_data  → dispatch("load_list")  → get_queryset → filter_queryset → serialize → data
save_note      → dispatch("save")       → validate_state → create|update → on_save_success → reset_state_fields? → refresh list
start_edit(id) → dispatch("start_edit") → get_object → populate state vars → bump form_reset_key
```

### Per-event `self.request` / `self.django_request`

Bound at the start of each **`dispatch`** (and list-only **`_load_*`**):

| Attr | Value |
|------|--------|
| `self.django_request` | `current_request()` — synthetic `HttpRequest` |
| `self.request` | `DjangoStateRequest` wrapper |
| `self.request.user` | Live `request.user` (use for ORM filters) |

```python
def get_queryset(self):
    return Note.objects.filter(user=self.request.user)
```

### Scoping (no default owner field)

Framework does **not** auto-filter by user. Prefer **`self.request.user`** in hooks (available after bind):

```python
def get_queryset(self):
    return Note.objects.filter(user=self.request.user)

def get_object_lookup(self, pk: int) -> dict:
    return {"pk": pk, "user": self.request.user}

def get_create_kwargs(self, state_data: dict) -> dict:
    return {**state_data, "user": self.request.user}
```

**Shortcut:** `class NotesState(AppState, ModelCRUDView, UserScopedMixin):` with `scope_field = "user_id"`. Assembly injects the three hooks (Reflex MRO cannot prioritize plain mixins).

### Page wiring example

```python
def notes_page() -> rx.Component:
    return rx.vstack(
        rx.cond(NotesState.error != "", rx.callout(NotesState.error)),
        rx.form(
            rx.vstack(
                rx.input(value=NotesState.title, on_change=NotesState.set_title),
                rx.text_area(value=NotesState.content, on_change=NotesState.set_content),
                spacing="3",
                width="100%",
            ),
            key=NotesState.form_reset_key,
            width="100%",
        ),
        rx.button("Save", on_click=NotesState.save_note),
        rx.foreach(
            NotesState.data,
            lambda n: rx.button("Edit", on_click=NotesState.start_edit(n["id"])),
        ),
    )

# app.add_page(notes_page, route="/notes", on_load=NotesState.on_load_data)
```

### Validation hooks (state-centric names — not `form_*`)

| Hook | When |
|------|------|
| `get_state_data()` | Read vars → dict |
| `validate_state(ctx, data)` | Cross-field errors → `dict[str, str]` |
| `clean_<field>(value)` | Per-field; return error string |
| `clean_state(data)` | Normalize before save |
| `on_state_invalid(ctx, errors)` | Set `error_var` / `field_errors` |
| `on_state_valid(ctx, state_data)` | Before create/update |
| `perform_create(ctx, state_data)` | ORM create |
| `perform_update(ctx, instance, state_data)` | ORM update |

Set `run_model_validation = True` to call Django `full_clean()`. Set `structured_errors = True` for `field_errors` (`Meta.field_errors_var`).

### Read-only lists

```python
class LogState(AppState, ModelListView):
    serializer_class = LogSerializer
```

### Permissions

```python
from reflex_django.state.mixins import IsAuthenticated, PermissionMixin

permission_classes = (IsAuthenticated,)  # on ModelCRUDView subclass Meta or class attr
```

### Do not use

- **`crud_mixin` / `ModelCRUDConfig`** — removed; use `ModelCRUDView`.
- **`owner_field`** on serializer — removed; use `get_queryset` / `UserScopedMixin`.
- **`Meta.form_fields`** — use **`Meta.state_fields`**.
- **`_clear_form`** — use **`reset_state_fields`** (alias **`_reset_state_fields`**).
- After save/update/cancel and when entering edit mode, wrap fields in **`rx.form(..., key=State.form_reset_key)`** so the DOM remounts (needed for controlled **`value=`** / **`on_change=`** too, not only **`name=`** inputs).
- **`bump_form_reset_key()`** — remount only; **`reset_state_fields()`** — clear vars + remount.

### Submodule map

`reflex_django/state/` — `views/crud.py` (`ModelCRUDView`), `assembly.py`, `options.py`, `mixins/` (`dispatch`, `state_fields`, `queryset`, `scoping`, …), `backends/django.py`.

---

## CLI

- **Primary dev:** `python manage.py run_reflex` — Vite + Reflex backend with in-process Django.
- **Django management:** `python manage.py migrate`, `createsuperuser`, `collectstatic`, etc.
- **Production build:** `python manage.py export_reflex --frontend-only --no-zip --stage-to-static-root`
- **Legacy:** `uv run reflex django <subcommand>` and `uv run reflex-django <subcommand>` still forward to Django when using older layouts.

---

## Testing and advanced use

- Use **`begin_event_request(request)`** / **`end_event_request()`** to bind a synthetic request in tests or advanced flows (normally the bridge does this). Examples: `reflex_django_tests/`.
- Use **`current_user()`**, **`current_request()`**, **`current_messages()`**, etc. inside bridged handlers for per-event Django context.

---

## Common mistakes

| Mistake | Why it fails |
|---------|----------------|
| Missing `import myapp.views` in `urls.py` | Pages never register; blank UI or missing routes. Use `RX_PAGE_PACKAGES` for nonstandard module paths. |
| Using `from reflex_django import make_dispatcher` | Removed in v3; use `from reflex_django.asgi.app import make_dispatcher`. |
| Using `DjangoUserState` for authorization | Client-visible; can be stale or tampered with—use `current_user()` / permissions on the server. |
| Putting non-JSON values into Reflex state or explicit context processors | Serialization errors or subtle runtime failures. |
| `install_event_bridge=False` but still expecting `current_user()` from sessions | No synthetic request / session binding from the bridge. |
| Heavy imports before Django setup / `rxconfig` | Breaks lazy-loading assumptions; circular import issues. |
| Relying on Django HTTP middleware for Reflex-only actions | Events are not full HTTP requests; use the event bridge and explicit checks. |
| Expecting `crud_mixin` or `owner_field` on ModelState | Removed; use `ModelCRUDView` + `get_queryset` / `UserScopedMixin`. |
| Using `form_title` / `Meta.form_fields` | Use flat `title` vars and `Meta.state_fields`. |

---

## Pointers for deeper reading

- `README.md` — full architecture, examples for states, bridges, context processors.
- `docs/reference/migration/v3_cleanup.md` — v3 breaking changes.
- `CHANGELOG.md` — version-to-version changes.
- `RELEASING.md` — maintainer release process.
- Source: `src/reflex_django/` — domain packages: `asgi/`, `runtime/integration/`, `bridge/event/`, `django/`, `dev/`, `setup/`, `mount/`, `auth/`, `states/`, `state/assembly/`, `management/commands/run_reflex/`, `cli/`. See `docs/reference/api.md` for import paths.
