There are three separate pieces to follow: the Python field, the HTML input produced by its widget, and the JavaScript editor attached to that input. Keep the existing form working as a textarea while you connect them.
Start with the field that already saves correctly
Suppose an internal training form has a body field containing “Bring your badge.” Its author needs to emphasize “badge” without losing the sentence when saving. This is an illustrative integration case, not a captured application.
Submit the original textarea once in your development environment and reopen that record. If ordinary text does not survive, fix the existing form or save route before adding a rich editor. Otherwise, a JavaScript problem and a server problem will produce the same apparent symptom.
Django distinguishes field validation from widget rendering. A textarea widget can carry attributes that your integration uses to find it, while the field still handles submitted data. Choose the widget on the actual form class used by the view; changing an unused form will leave the page unchanged. Django widgets
Render the assets and initialize the right element
A custom widget can declare CSS and JavaScript through its Media definition. In a custom form template, render the form's media as well as the fields. Django's admin has its own widget-media handling; a working admin page does not prove your custom template includes those files. Form assets
In the rendered page, inspect the actual textarea's name and id. Form prefixes can change them. Initialize against the generated element, rather than assuming every form has an element called id_body. On a page with several form rows, attach one editor to each intended field and avoid initializing the same element twice.
Use the editor library's documented ready and change hooks. Do not conceal the fallback textarea until initialization succeeds. A missing script should leave readable, editable content instead of an empty panel.
Follow one edit into the request
Change the training sentence to “Bring your badge and visitor pass.” Before saving, confirm that the underlying submitted field contains that current value through the library's documented synchronization route. An editor may keep a separate model; reading the textarea too early can capture the old sentence.
Inspect the form request in your own development browser. Check the field name, the current content, and the server response. Then reopen the saved record in the editor. These observations identify where a failure happens:
- Correct editor, stale request: inspect synchronization before submission.
- Correct request, stale reopened record: inspect validation and persistence.
- Correct saved record, different public formatting: inspect the rendering policy.
Retain form validation messages and normal CSRF handling. Rich editing should not create a separate save path that bypasses the form's existing checks.
Decide which HTML the application accepts
Choose supported headings, lists, emphasis, and links before accepting formatted content. An editor toolbar is an authoring interface; the server still needs an appropriate HTML sanitization policy. Do not add Django's safe filter to arbitrary submitted HTML just to make tags render.
For display text, Django's escaping remains useful. For intentionally rendered rich HTML, establish the sanitization boundary and test allowed and rejected content in the actual application. The structured rich-text example explains why plain text and formatted output are different representations.
Finish with the reopened record and the actual reader view. The training sentence should contain the new words, the intended emphasis, and no unexplained loss after a second save. Keep durable corrections in Django's saved content; an HTML review copy cannot update the form's database record.