Skip to main content

Python integrations and packaged browser assets for using OllowEditor with Django, Django REST Framework, Flask, and FastAPI.

Project description

OllowEditor for Python

Python CI License: MIT

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.js
    • olloweditor.css
    • olloweditor-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 OllowEditor extension
  • 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:

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.css
  • olloweditor/olloweditor.browser.js
  • olloweditor/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.js
  • olloweditor.css
  • olloweditor-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 OllowEditor blueprint
  • 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.whl
  • dist/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.staticfiles is installed
  • olloweditor.apps.OllowEditorConfig is in INSTALLED_APPS
  • collectstatic has 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) or init_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:

  1. Fork the repository.
  2. Create a branch for your change.
  3. Add or update tests.
  4. Run the frontend and Python verification commands.
  5. Open a pull request.

License

OllowEditor is released under the MIT License.

Project links

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

olloweditor-0.1.0.tar.gz (129.5 kB view details)

Uploaded Source

Built Distribution

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

olloweditor-0.1.0-py3-none-any.whl (117.3 kB view details)

Uploaded Python 3

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

Hashes for olloweditor-0.1.0.tar.gz
Algorithm Hash digest
SHA256 ca4dadbce43fec2bbed62e7e3278de691302ce36b691320fb4bafe23d5961988
MD5 51c4661b2f9c5c728068f64dd6a9999e
BLAKE2b-256 396cc8bafe81fa6a63760b024f8c16521120eaa2c14f7f983d67f3b53e7ed0bb

See more details on using hashes here.

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

Hashes for olloweditor-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 34664bcbe6d24051906c9baadd733a9e99484260797c1f46e28e6a7b928bdf0e
MD5 6b643a1d133c2d47b1ef80369133473a
BLAKE2b-256 7d06952fa989bec2b28964494d9d3e835ba2edc1549182f95a50a9dcfec8efd4

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