Python integrations and packaged browser assets for using OllowEditor with Django, Django REST Framework, Flask, and FastAPI.
Project description
OllowEditor for Python
OllowEditor for Python packages the compiled OllowEditor browser assets and provides integrations for Django, Django REST Framework, Flask, and FastAPI.
The editor itself remains a JavaScript and CSS application. This package does not reimplement the editor in Python. Instead, it distributes the browser bundle, stylesheet, and shared initialization script, then adds Python helpers for serving those assets and wiring the editor into forms, templates, and serializer fields.
OllowEditor runs in the browser, keeps a <textarea> synchronized with generated HTML, and submits that HTML through normal form posts or JSON payloads. If your application accepts untrusted HTML, you still need server-side validation and sanitization.
Introduction
The olloweditor package is intended for Python applications that want to use the OllowEditor frontend without managing a separate npm-based asset pipeline. It ships the compiled assets inside the Python distribution and exposes framework-specific helpers where they reduce integration work.
Official integrations are included for:
- Django
- Django REST Framework
- Flask
- FastAPI
The base install remains framework-independent. Installing olloweditor alone gives you packaged assets and resource helpers without pulling in Django, Flask, FastAPI, or Django REST Framework.
Key features
Python integration features
- Packaged frontend assets:
olloweditor.browser.jsolloweditor.cssolloweditor-init.js
- Base install without framework dependencies
- Safe packaged-resource helpers:
get_static_root()get_asset_path(filename)asset_exists(filename)
- Django
OllowEditorWidget - Django
OllowEditorField - Django admin and staticfiles support
- Django REST Framework
OllowEditorHTMLField - Optional DRF sanitizer callback
- Flask
OllowEditorextension - Flask asset blueprint and Jinja helpers
- FastAPI static mount helper and template helpers
- Shared automatic initialization for marked textareas
- Support for multiple independent editor instances
- Per-editor configuration through widget options or
data-olloweditor-options
OllowEditor frontend capabilities
- Rich-text formatting and typography controls
- Lists, alignment, links, and bookmarks
- Images, galleries, tables, and code blocks
- YouTube embeds and editorial blocks
- Markdown import/export, HTML export, and PDF export
- Responsive editing UI and plugin API
- Textarea synchronization for normal backend form handling
The full frontend feature reference lives in the main project documentation:
- Main repository: https://github.com/CodeFortifyCloud/olloweditor
- Main project README: https://github.com/CodeFortifyCloud/olloweditor/blob/pip/README.md
Supported environments
| Component | Supported version |
|---|---|
| Python | >=3.10 |
| Django | >=4.2 |
| Django REST Framework | >=3.15 |
| Flask | >=3.0 |
| FastAPI | >=0.110 |
These are the package minimums declared in python/pyproject.toml. They are not a promise that every older dependency combination receives the same test coverage as the current CI matrix.
Installation
Base package
pip install olloweditor
This installs the packaged browser assets and framework-independent helpers only.
Django
pip install "olloweditor[django]"
Django REST Framework
pip install "olloweditor[drf]"
The drf extra also installs Django because Django REST Framework depends on it.
Flask
pip install "olloweditor[flask]"
FastAPI
pip install "olloweditor[fastapi]"
All integrations
pip install "olloweditor[all]"
Most projects should install only the extra they actually use.
Production PyPI publication has not been completed yet. Until that happens, install from a local wheel or editable checkout during development.
Integration overview
| Framework | Main integration |
|---|---|
| Django | Form widget, model field, staticfiles integration, and admin support |
| Django REST Framework | Serializer field for OllowEditor-generated HTML |
| Flask | Extension, packaged asset blueprint, and Jinja helpers |
| FastAPI | Static asset mounting and template helpers |
Django quick start
Install
pip install "olloweditor[django]"
Add the application
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"olloweditor.apps.OllowEditorConfig",
]
Use the model field
from django.db import models
from olloweditor.integrations.django import OllowEditorField
class Article(models.Model):
title = models.CharField(max_length=255)
content = OllowEditorField()
Run migrations:
python manage.py makemigrations
python manage.py migrate
Use the widget with an existing field
from django import forms
from olloweditor.integrations.django import OllowEditorWidget
from .models import Article
class ArticleForm(forms.ModelForm):
content = forms.CharField(
widget=OllowEditorWidget(
options={
"theme": "auto",
}
)
)
class Meta:
model = Article
fields = ["title", "content"]
Render the form
<form method="post">
{% csrf_token %}
{{ form.media }}
{{ form.as_p }}
<button type="submit">Save article</button>
</form>
{{ form.media }} includes:
olloweditor/olloweditor.cssolloweditor/olloweditor.browser.jsolloweditor/olloweditor-init.js
Static files
python manage.py collectstatic
Admin
OllowEditorField uses OllowEditorWidget in generated ModelForms, including normal Django admin form construction once olloweditor.apps.OllowEditorConfig is installed.
Django REST Framework quick start
Django REST Framework does not render the JavaScript editor for external API clients. It accepts the HTML string generated by an OllowEditor frontend.
Install
pip install "olloweditor[drf]"
Serializer example
from rest_framework import serializers
from olloweditor.integrations.drf import OllowEditorHTMLField
class ArticleSerializer(serializers.Serializer):
title = serializers.CharField()
content = OllowEditorHTMLField(
allow_blank=True,
required=False,
)
JSON request example
{
"title": "Introducing OllowEditor",
"content": "<p>Rich text generated by OllowEditor.</p>"
}
Sanitizer callback
OllowEditorHTMLField accepts sanitizer: Callable[[str], str].
def sanitize_article_html(value: str) -> str:
return trusted_html_sanitizer.clean(value)
class ArticleSerializer(serializers.Serializer):
title = serializers.CharField()
content = OllowEditorHTMLField(
sanitizer=sanitize_article_html,
)
trusted_html_sanitizer is your application’s sanitizer choice. The package does not bundle one automatically.
Flask quick start
Install
pip install "olloweditor[flask]"
Application setup
from flask import Flask, render_template, request
from olloweditor.integrations.flask import OllowEditor
app = Flask(__name__)
olloweditor = OllowEditor(app)
@app.route("/", methods=["GET", "POST"])
def index():
content = ""
if request.method == "POST":
content = request.form.get("content", "")
return render_template("index.html", content=content)
Template
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>OllowEditor with Flask</title>
{{ olloweditor_assets() }}
</head>
<body>
<form method="post">
<textarea
id="content"
name="content"
data-olloweditor="true"
>{{ content }}</textarea>
<button type="submit">Save article</button>
</form>
</body>
</html>
Application factory
from flask import Flask
from olloweditor.integrations.flask import OllowEditor
olloweditor = OllowEditor()
def create_app() -> Flask:
app = Flask(__name__)
olloweditor.init_app(app)
return app
FastAPI quick start
Install
pip install "olloweditor[fastapi]"
Application setup
from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates
from olloweditor.integrations.fastapi import (
mount_olloweditor,
olloweditor_assets,
)
app = FastAPI()
mount_olloweditor(app)
templates = Jinja2Templates(directory="templates")
templates.env.globals["olloweditor_assets"] = olloweditor_assets
@app.get("/")
def index(request: Request):
return templates.TemplateResponse(
request=request,
name="index.html",
context={},
)
Template
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>OllowEditor with FastAPI</title>
{{ olloweditor_assets() }}
</head>
<body>
<form method="post">
<textarea
id="content"
name="content"
data-olloweditor="true"
></textarea>
<button type="submit">Save article</button>
</form>
</body>
</html>
If your FastAPI application processes HTML form submissions, install:
pip install python-multipart
That package is not required just to serve OllowEditor assets.
Packaged frontend assets
Installing olloweditor gives you:
olloweditor.browser.jsolloweditor.cssolloweditor-init.js
The shared initializer looks for:
<textarea
name="content"
data-olloweditor="true"
data-olloweditor-options='{"theme":"auto"}'
></textarea>
Framework behavior:
- Django serves assets through staticfiles
- Flask serves assets through the
OllowEditorblueprint - FastAPI serves assets through
StaticFiles - the base package exposes resource helpers through
olloweditor.resources
Per-editor configuration
Django widget example:
from olloweditor.integrations.django import OllowEditorWidget
widget = OllowEditorWidget(
options={
"theme": "auto",
}
)
HTML data-attribute example:
<textarea
name="content"
data-olloweditor="true"
data-olloweditor-options='{"theme":"auto"}'
></textarea>
For the full JavaScript option surface, use the main project documentation.
Working with submitted content
OllowEditor keeps the original textarea value synchronized with HTML. Your backend receives that HTML through the normal request path.
Django
content = request.POST.get("content", "")
Flask
content = request.form.get("content", "")
FastAPI
from typing import Annotated
from fastapi import Form
def create_article(
content: Annotated[str, Form()],
):
return {"content": content}
Django REST Framework
{
"content": "<p>Article content</p>"
}
Storage, validation, sanitization, and rendering remain the application’s responsibility.
Security and HTML sanitization
OllowEditor generates HTML. That matters for your trust model.
- Client-side cleanup is not a complete security boundary.
- Untrusted HTML can still carry XSS and related risks.
- Server-side applications should validate and sanitize untrusted HTML before rendering it.
- Your application should define allowed tags, attributes, URL schemes, image sources, and embed providers.
- Upload endpoints need their own validation for authorization, CSRF, MIME type, extension, file size, storage destination, and rate limiting where appropriate.
- Django
safe, Jinja|safe,Markup, or equivalent should only be used after content has been sanitized or otherwise explicitly trusted.
The package does not claim that arbitrary HTML is safe automatically.
Framework dependency isolation
The base install stays lightweight:
pip install olloweditor
That does not install Django, Django REST Framework, Flask, or FastAPI. Install only the extra you need:
pip install "olloweditor[django]"
This avoids unnecessary dependency conflicts in applications that only need one integration.
Example applications
Examples are included under python/examples/:
- Django example — form workflow, model field, admin, and staticfiles
- DRF example — serializer field and JSON API workflow
- Flask example — extension, asset blueprint, template helper, and form submission
- FastAPI example — asset mount, template helper, and form submission
Development
From the repository root:
npm ci
npm run build
npm run typecheck
npm test
npm run build:python-assets
npm run verify:python-assets
Then for Python work:
cd python
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e ".[all,dev,test]"
Testing
Run the Python checks from python/:
python -m pytest
python -m ruff check .
python -m ruff format --check .
python -m mypy src
The repository also includes:
- isolated wheel-install verification
- packaged-asset verification
- framework integration tests
- example smoke tests
- TestPyPI release verification tooling
Building distributions
cd python
rm -rf build dist src/*.egg-info
python -m build
python -m twine check dist/*
Expected outputs:
dist/olloweditor-<version>-py3-none-any.whldist/olloweditor-<version>.tar.gz
Local wheel verification
Prefer testing the built wheel, not only an editable install:
pip install dist/olloweditor-<version>-py3-none-any.whl
With an extra:
pip install "olloweditor[django] @ file:///path/to/dist/olloweditor-<version>-py3-none-any.whl"
The repository also includes:
python scripts/check_wheel_contents.py dist/*.whl
python scripts/verify_wheel_installs.py dist/*.whl
Troubleshooting
The editor does not appear
Check:
- the CSS and JavaScript assets are actually loaded
- the browser bundle loads before
olloweditor-init.js - the textarea includes
data-olloweditor="true" - the browser console does not show initialization errors
Django assets return 404
Check:
django.contrib.staticfilesis installedolloweditor.apps.OllowEditorConfigis inINSTALLED_APPScollectstatichas been run where required- your production staticfiles serving is configured correctly
form.media is missing
Render:
{{ form.media }}
Flask assets return 404
Check:
OllowEditor(app)orinit_app(app)was called- the configured URL prefix is what your template expects
{{ olloweditor_assets() }}renders the expected URLs
FastAPI assets return 404
Check:
mount_olloweditor(app)was called- the mount path matches the helper output
- no conflicting route already uses that path
ImportError for a framework integration
Install the matching extra:
pip install "olloweditor[fastapi]"
Invalid editor options
data-olloweditor-options must contain valid JSON.
Relationship to the npm package
The npm package is still the primary frontend distribution:
npm install @codefortify/olloweditor
Use the npm package when your project already has a frontend build pipeline and wants to consume the editor directly from JavaScript or TypeScript.
Use the Python package when you want:
- packaged browser assets inside Python distributions
- Django, DRF, Flask, or FastAPI integration helpers
- framework-specific form, template, or serializer support
Contributing
If you want to contribute:
- Fork the repository.
- Create a branch for your change.
- Add or update tests.
- Run the frontend and Python verification commands.
- Open a pull request.
License
OllowEditor is released under the MIT License.
Project links
- Repository: https://github.com/CodeFortifyCloud/olloweditor
- Python package docs: https://github.com/CodeFortifyCloud/olloweditor/tree/pip/python
- Main project README: https://github.com/CodeFortifyCloud/olloweditor/blob/main/README.md
- npm package source: https://github.com/CodeFortifyCloud/olloweditor
- Issue tracker: https://github.com/CodeFortifyCloud/olloweditor/issues
- Release process notes: https://github.com/CodeFortifyCloud/olloweditor/blob/pip/python/docs/release.md
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file olloweditor-0.1.0.tar.gz.
File metadata
- Download URL: olloweditor-0.1.0.tar.gz
- Upload date:
- Size: 129.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ca4dadbce43fec2bbed62e7e3278de691302ce36b691320fb4bafe23d5961988
|
|
| MD5 |
51c4661b2f9c5c728068f64dd6a9999e
|
|
| BLAKE2b-256 |
396cc8bafe81fa6a63760b024f8c16521120eaa2c14f7f983d67f3b53e7ed0bb
|
File details
Details for the file olloweditor-0.1.0-py3-none-any.whl.
File metadata
- Download URL: olloweditor-0.1.0-py3-none-any.whl
- Upload date:
- Size: 117.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
34664bcbe6d24051906c9baadd733a9e99484260797c1f46e28e6a7b928bdf0e
|
|
| MD5 |
6b643a1d133c2d47b1ef80369133473a
|
|
| BLAKE2b-256 |
7d06952fa989bec2b28964494d9d3e835ba2edc1549182f95a50a9dcfec8efd4
|