maykin-django-prosemirror


Namemaykin-django-prosemirror JSON
Version 0.2.0 PyPI version JSON
download
home_pageNone
SummaryRich-text fields for Django using Prosemirror - a powerful, schema-driven rich text editor.
upload_time2025-10-14 08:34:38
maintainerNone
docs_urlNone
authorNone
requires_python>=3.11
licenseCopyright 2025 Maykin Media Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keywords django prosemirror rich-text editor document json wysiwyg content editor text editor markdown html
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            

django-prosemirror
==================

:Version: 0.2.0
:Source: https://github.com/maykinmedia/django_prosemirror
:Keywords: Django, Prosemirror, rich-text, editor, document, JSON, WYSIWYG, content editor, text editor, markdown, html
:PythonVersion: 3.11+

|build-status| |code-quality| |ruff| |coverage| |docs|

|python-versions| |django-versions| |pypi-version|

Rich-text fields for Django using `Prosemirror <https://prosemirror.net/>`_ -
a powerful, schema-driven rich text editor.

.. contents::

.. section-numbering::

Features
========

* **Rich-text editing**: Full-featured Prosemirror editor integration with Django
  (admin) forms
* **Bidirectional conversion**: Seamless conversion between HTML and ProseMirror
  document format
* **Configurable schemas**: Fine-grained control over allowed content (headings, links,
  images, tables, etc.)
* **Native ProseMirror storage**: Documents are stored in their native Prosemirror
  format, preserving structure and enabling programmatic manipulation without HTML parsing

Installation
============

Requirements
------------

* Python 3.11 or above
* Django 4.2 or newer

Install
-------

.. code-block:: bash

    pip install maykin-django-prosemirror

Add to your Django settings:

.. code-block:: python

    INSTALLED_APPS = [
        # ... your other apps
        'django_prosemirror',
    ]

Usage
=====

Model Field
-----------

Use ``ProseMirrorModelField`` in your Django models:

.. code-block:: python

    from django.db import models
    from django_prosemirror.fields import ProseMirrorModelField
    from django_prosemirror.schema import NodeType, MarkType

    class BlogPost(models.Model):
        title = models.CharField(max_length=200)

        # Full-featured rich text content (uses default configuration allowing all node
        # and mark types)
        content = ProseMirrorModelField()

        # Limited schema - only headings and paragraphs with bold text
        summary = ProseMirrorModelField(
            allowed_node_types=[NodeType.PARAGRAPH, NodeType.HEADING],
            allowed_mark_types=[MarkType.STRONG],
            null=True,
            blank=True
        )

        # Default document
        content_with_prompt = ProseMirrorModelField(
            default=lambda: {
                "type": "doc",
                "content": [
                    {
                        "type": "paragraph",
                        "content": [{"type": "text", "text": "Start writing..."}]
                    }
                ]
            }
        )

Accessing Content
-----------------

The field provides both document and HTML representations:

.. code-block:: python

    post = BlogPost.objects.get(pk=1)

    # Access as ProseMirror document (dict)
    doc_content = post.content.doc
    # Output: {
    #     "type": "doc",
    #     "content": [
    #         {
    #             "type": "heading",
    #             "attrs": {"level": 1},
    #             "content": [{"type": "text", "text": "Heading"}]
    #         },
    #         {
    #             "type": "paragraph",
    #             "content": [
    #                 {"type": "text", "text": "Paragraph content..."}
    #             ]
    #         }
    #     ]
    # }

    # Access as HTML
    html_content = post.content.html
    # Output: "<h1>Heading</h1><p>Paragraph content...</p>"

    # Modify content from HTML, which will be converted to a Prosemirror document internally
    post.content.html = "<h2>New heading</h2><p>Updated content</p>"
    post.save()

    # After modification, the document structure is updated
    updated_doc = post.content.doc
    # Output: {
    #     "type": "doc",
    #     "content": [
    #         {
    #             "type": "heading",
    #             "attrs": {"level": 2},
    #             "content": [{"type": "text", "text": "New heading"}]
    #         },
    #         {
    #             "type": "paragraph",
    #             "content": [{"type": "text", "text": "Updated content"}]
    #         }
    #     ]
    # }

Form Field
----------

Use ``ProsemirrorFormField`` in Django forms:

.. code-block:: python

    from django import forms
    from django_prosemirror.fields import ProsemirrorFormField
    from django_prosemirror.schema import NodeType, MarkType

    class BlogPostForm(forms.Form):
        title = forms.CharField(max_length=200)

        # Full-featured editor (uses default configuration)
        content = ProsemirrorFormField()

        # Limited to headings and paragraphs with basic formatting
        summary = ProsemirrorFormField(
            allowed_node_types=[NodeType.PARAGRAPH, NodeType.HEADING],
            allowed_mark_types=[MarkType.STRONG, MarkType.ITALIC],
            required=False
        )

Schema Configuration
--------------------

Control exactly what content types are allowed using node and mark types:

.. important::
   You must always include ``NodeType.PARAGRAPH`` in your ``allowed_node_types`` list.
   The field will raise a ``ValueError`` if omitted.

.. code-block:: python

    from django_prosemirror.schema import NodeType, MarkType

    # Available node types
    NodeType.PARAGRAPH         # Paragraphs (required)
    NodeType.HEADING           # Headings (h1-h6)
    NodeType.BLOCKQUOTE        # Quote blocks
    NodeType.HORIZONTAL_RULE   # Horizontal rules
    NodeType.CODE_BLOCK        # Code blocks
    NodeType.FILER_IMAGE       # Images (requires django-filer)
    NodeType.HARD_BREAK        # Line breaks
    NodeType.BULLET_LIST       # Bullet lists
    NodeType.ORDERED_LIST      # Numbered lists
    NodeType.LIST_ITEM         # List items
    NodeType.TABLE             # Tables
    NodeType.TABLE_ROW         # Table rows
    NodeType.TABLE_CELL        # Table data cells
    NodeType.TABLE_HEADER      # Table header cells

    # Available mark types
    MarkType.STRONG            # Bold text
    MarkType.ITALIC            # Italic text (em)
    MarkType.UNDERLINE         # Underlined text
    MarkType.STRIKETHROUGH     # Strikethrough text
    MarkType.CODE              # Inline code
    MarkType.LINK              # Links

    # Custom configurations
    BASIC_FORMATTING = {
        'allowed_node_types': [NodeType.PARAGRAPH, NodeType.HEADING],
        'allowed_mark_types': [MarkType.STRONG, MarkType.ITALIC, MarkType.LINK],
    }

    BLOG_EDITOR = {
        'allowed_node_types': [
            NodeType.PARAGRAPH,
            NodeType.HEADING,
            NodeType.BLOCKQUOTE,
            NodeType.IMAGE,
            NodeType.BULLET_LIST,
            NodeType.ORDERED_LIST,
            NodeType.LIST_ITEM,
        ],
        'allowed_mark_types': [
            MarkType.STRONG,
            MarkType.ITALIC,
            MarkType.LINK,
            MarkType.CODE,
        ],
    }

    TABLE_EDITOR = {
        'allowed_node_types': [
            NodeType.PARAGRAPH,
            NodeType.HEADING,
            NodeType.TABLE,
            NodeType.TABLE_ROW,
            NodeType.TABLE_CELL,
            NodeType.TABLE_HEADER,
        ],
        'allowed_mark_types': [MarkType.STRONG, MarkType.ITALIC],
    }

    # Use in fields
    class DocumentModel(models.Model):
        blog_content = ProseMirrorModelField(**BLOG_EDITOR)
        table_content = ProseMirrorModelField(**TABLE_EDITOR)

Default Values
--------------

Always use callables for default values returning valid ProseMirror documents:

.. code-block:: python

    class Article(models.Model):
        # ✅ Correct: Using a callable
        content = ProseMirrorModelField(
            default=lambda: {"type": "doc", "content": []}
        )

        # ❌ Wrong: Static dict (validation error)
        # content = ProseMirrorModelField(
        #     default={"type": "doc", "content": []}
        # )

Django Admin Integration
------------------------

The field works automatically with Django admin:

.. code-block:: python

    from django.contrib import admin
    from .models import BlogPost

    @admin.register(BlogPost)
    class BlogPostAdmin(admin.ModelAdmin):
        fields = ['title', 'content', 'summary']
        readonly_fields = ['summary']  # Read-only fields render as HTML

        # Editable fields: Render the full ProseMirror rich-text editor
        # Read-only fields: Render as formatted HTML output


Frontend Integration
--------------------

**Required Assets**: The ProseMirror form fields require both CSS and JavaScript assets to function. These assets are **mandatory** for any template that renders ProseMirror form fields - without them, the rich text editor will not work.

.. code-block:: html

    {% load django_prosemirror %}
    <!DOCTYPE html>
    <html>
    <head>
        {% include_django_prosemirror_css %}
        {% include_django_prosemirror_js_defer %}
    </head>
    <body>
        {{ form.as_p }}
    </body>
    </html>

**Note**: These assets are only required for form rendering (editing). Displaying saved content using ``{{ post.content.html }}`` in templates does not require these assets.

Advanced Usage
==============

Programmatic Content Creation
-----------------------------

Create ProseMirror content programmatically:

.. code-block:: python

    # Create a document with heading and paragraph
    content = {
        "type": "doc",
        "content": [
            {
                "type": "heading",
                "attrs": {"level": 1},
                "content": [{"type": "text", "text": "My Heading"}]
            },
            {
                "type": "paragraph",
                "content": [
                    {"type": "text", "text": "Some "},
                    {
                        "type": "text",
                        "marks": [{"type": "strong"}],
                        "text": "bold"
                    },
                    {"type": "text", "text": " text."}
                ]
            }
        ]
    }

    article = Article.objects.create(content=content)


Local development
=================

Requirements for development:

* Node.js (for building frontend assets)
* All runtime requirements listed above

Setup for development:

.. code-block:: bash

    python -mvirtualenv .venv
    source .venv/bin/activate

    # Install Python package in development mode
    pip install -e .[tests,coverage,docs,release]

    # Install Node.js dependencies
    npm install

    # Build frontend assets (when making changes to JavaScript)
    ./build.sh

When running management commands via ``django-admin``, make sure to add the root
directory to the python path (or use ``python -m django <command>``):

.. code-block:: bash

    export PYTHONPATH=. DJANGO_SETTINGS_MODULE=testapp.settings
    django-admin migrate
    django-admin createsuperuser  # optional
    django-admin runserver


.. |build-status| image:: https://github.com/maykinmedia/django_prosemirror/workflows/Run%20CI/badge.svg
    :alt: Build status
    :target: https://github.com/maykinmedia/django_prosemirror/actions?query=workflow%3A%22Run+CI%22

.. |code-quality| image:: https://github.com/maykinmedia/django_prosemirror/workflows/Code%20quality%20checks/badge.svg
     :alt: Code quality checks
     :target: https://github.com/maykinmedia/django_prosemirror/actions?query=workflow%3A%22Code+quality+checks%22

.. |ruff| image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
    :target: https://github.com/astral-sh/ruff
    :alt: Ruff

.. |coverage| image:: https://codecov.io/gh/maykinmedia/django_prosemirror/branch/main/graph/badge.svg
    :target: https://codecov.io/gh/maykinmedia/django_prosemirror
    :alt: Coverage status

.. |docs| image:: https://readthedocs.org/projects/django_prosemirror/badge/?version=latest
    :target: https://django_prosemirror.readthedocs.io/en/latest/?badge=latest
    :alt: Documentation Status

.. |python-versions| image:: https://img.shields.io/pypi/pyversions/maykin-django-prosemirror.svg

.. |django-versions| image:: https://img.shields.io/pypi/djversions/maykin-django-prosemirror.svg

.. |pypi-version| image:: https://img.shields.io/pypi/v/maykin-django-prosemirror.svg
    :target: https://pypi.org/project/maykin-django-prosemirror/

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "maykin-django-prosemirror",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.11",
    "maintainer_email": null,
    "keywords": "Django, Prosemirror, rich-text, editor, document, JSON, WYSIWYG, content editor, text editor, markdown, html",
    "author": null,
    "author_email": "Maykin Media <support@maykinmedia.nl>",
    "download_url": "https://files.pythonhosted.org/packages/e8/ca/8dafe041d41590e3cc1acc864fe63d7aff29a92d4b9a1e0f0899c011d44c/maykin_django_prosemirror-0.2.0.tar.gz",
    "platform": null,
    "description": "\n\ndjango-prosemirror\n==================\n\n:Version: 0.2.0\n:Source: https://github.com/maykinmedia/django_prosemirror\n:Keywords: Django, Prosemirror, rich-text, editor, document, JSON, WYSIWYG, content editor, text editor, markdown, html\n:PythonVersion: 3.11+\n\n|build-status| |code-quality| |ruff| |coverage| |docs|\n\n|python-versions| |django-versions| |pypi-version|\n\nRich-text fields for Django using `Prosemirror <https://prosemirror.net/>`_ -\na powerful, schema-driven rich text editor.\n\n.. contents::\n\n.. section-numbering::\n\nFeatures\n========\n\n* **Rich-text editing**: Full-featured Prosemirror editor integration with Django\n  (admin) forms\n* **Bidirectional conversion**: Seamless conversion between HTML and ProseMirror\n  document format\n* **Configurable schemas**: Fine-grained control over allowed content (headings, links,\n  images, tables, etc.)\n* **Native ProseMirror storage**: Documents are stored in their native Prosemirror\n  format, preserving structure and enabling programmatic manipulation without HTML parsing\n\nInstallation\n============\n\nRequirements\n------------\n\n* Python 3.11 or above\n* Django 4.2 or newer\n\nInstall\n-------\n\n.. code-block:: bash\n\n    pip install maykin-django-prosemirror\n\nAdd to your Django settings:\n\n.. code-block:: python\n\n    INSTALLED_APPS = [\n        # ... your other apps\n        'django_prosemirror',\n    ]\n\nUsage\n=====\n\nModel Field\n-----------\n\nUse ``ProseMirrorModelField`` in your Django models:\n\n.. code-block:: python\n\n    from django.db import models\n    from django_prosemirror.fields import ProseMirrorModelField\n    from django_prosemirror.schema import NodeType, MarkType\n\n    class BlogPost(models.Model):\n        title = models.CharField(max_length=200)\n\n        # Full-featured rich text content (uses default configuration allowing all node\n        # and mark types)\n        content = ProseMirrorModelField()\n\n        # Limited schema - only headings and paragraphs with bold text\n        summary = ProseMirrorModelField(\n            allowed_node_types=[NodeType.PARAGRAPH, NodeType.HEADING],\n            allowed_mark_types=[MarkType.STRONG],\n            null=True,\n            blank=True\n        )\n\n        # Default document\n        content_with_prompt = ProseMirrorModelField(\n            default=lambda: {\n                \"type\": \"doc\",\n                \"content\": [\n                    {\n                        \"type\": \"paragraph\",\n                        \"content\": [{\"type\": \"text\", \"text\": \"Start writing...\"}]\n                    }\n                ]\n            }\n        )\n\nAccessing Content\n-----------------\n\nThe field provides both document and HTML representations:\n\n.. code-block:: python\n\n    post = BlogPost.objects.get(pk=1)\n\n    # Access as ProseMirror document (dict)\n    doc_content = post.content.doc\n    # Output: {\n    #     \"type\": \"doc\",\n    #     \"content\": [\n    #         {\n    #             \"type\": \"heading\",\n    #             \"attrs\": {\"level\": 1},\n    #             \"content\": [{\"type\": \"text\", \"text\": \"Heading\"}]\n    #         },\n    #         {\n    #             \"type\": \"paragraph\",\n    #             \"content\": [\n    #                 {\"type\": \"text\", \"text\": \"Paragraph content...\"}\n    #             ]\n    #         }\n    #     ]\n    # }\n\n    # Access as HTML\n    html_content = post.content.html\n    # Output: \"<h1>Heading</h1><p>Paragraph content...</p>\"\n\n    # Modify content from HTML, which will be converted to a Prosemirror document internally\n    post.content.html = \"<h2>New heading</h2><p>Updated content</p>\"\n    post.save()\n\n    # After modification, the document structure is updated\n    updated_doc = post.content.doc\n    # Output: {\n    #     \"type\": \"doc\",\n    #     \"content\": [\n    #         {\n    #             \"type\": \"heading\",\n    #             \"attrs\": {\"level\": 2},\n    #             \"content\": [{\"type\": \"text\", \"text\": \"New heading\"}]\n    #         },\n    #         {\n    #             \"type\": \"paragraph\",\n    #             \"content\": [{\"type\": \"text\", \"text\": \"Updated content\"}]\n    #         }\n    #     ]\n    # }\n\nForm Field\n----------\n\nUse ``ProsemirrorFormField`` in Django forms:\n\n.. code-block:: python\n\n    from django import forms\n    from django_prosemirror.fields import ProsemirrorFormField\n    from django_prosemirror.schema import NodeType, MarkType\n\n    class BlogPostForm(forms.Form):\n        title = forms.CharField(max_length=200)\n\n        # Full-featured editor (uses default configuration)\n        content = ProsemirrorFormField()\n\n        # Limited to headings and paragraphs with basic formatting\n        summary = ProsemirrorFormField(\n            allowed_node_types=[NodeType.PARAGRAPH, NodeType.HEADING],\n            allowed_mark_types=[MarkType.STRONG, MarkType.ITALIC],\n            required=False\n        )\n\nSchema Configuration\n--------------------\n\nControl exactly what content types are allowed using node and mark types:\n\n.. important::\n   You must always include ``NodeType.PARAGRAPH`` in your ``allowed_node_types`` list.\n   The field will raise a ``ValueError`` if omitted.\n\n.. code-block:: python\n\n    from django_prosemirror.schema import NodeType, MarkType\n\n    # Available node types\n    NodeType.PARAGRAPH         # Paragraphs (required)\n    NodeType.HEADING           # Headings (h1-h6)\n    NodeType.BLOCKQUOTE        # Quote blocks\n    NodeType.HORIZONTAL_RULE   # Horizontal rules\n    NodeType.CODE_BLOCK        # Code blocks\n    NodeType.FILER_IMAGE       # Images (requires django-filer)\n    NodeType.HARD_BREAK        # Line breaks\n    NodeType.BULLET_LIST       # Bullet lists\n    NodeType.ORDERED_LIST      # Numbered lists\n    NodeType.LIST_ITEM         # List items\n    NodeType.TABLE             # Tables\n    NodeType.TABLE_ROW         # Table rows\n    NodeType.TABLE_CELL        # Table data cells\n    NodeType.TABLE_HEADER      # Table header cells\n\n    # Available mark types\n    MarkType.STRONG            # Bold text\n    MarkType.ITALIC            # Italic text (em)\n    MarkType.UNDERLINE         # Underlined text\n    MarkType.STRIKETHROUGH     # Strikethrough text\n    MarkType.CODE              # Inline code\n    MarkType.LINK              # Links\n\n    # Custom configurations\n    BASIC_FORMATTING = {\n        'allowed_node_types': [NodeType.PARAGRAPH, NodeType.HEADING],\n        'allowed_mark_types': [MarkType.STRONG, MarkType.ITALIC, MarkType.LINK],\n    }\n\n    BLOG_EDITOR = {\n        'allowed_node_types': [\n            NodeType.PARAGRAPH,\n            NodeType.HEADING,\n            NodeType.BLOCKQUOTE,\n            NodeType.IMAGE,\n            NodeType.BULLET_LIST,\n            NodeType.ORDERED_LIST,\n            NodeType.LIST_ITEM,\n        ],\n        'allowed_mark_types': [\n            MarkType.STRONG,\n            MarkType.ITALIC,\n            MarkType.LINK,\n            MarkType.CODE,\n        ],\n    }\n\n    TABLE_EDITOR = {\n        'allowed_node_types': [\n            NodeType.PARAGRAPH,\n            NodeType.HEADING,\n            NodeType.TABLE,\n            NodeType.TABLE_ROW,\n            NodeType.TABLE_CELL,\n            NodeType.TABLE_HEADER,\n        ],\n        'allowed_mark_types': [MarkType.STRONG, MarkType.ITALIC],\n    }\n\n    # Use in fields\n    class DocumentModel(models.Model):\n        blog_content = ProseMirrorModelField(**BLOG_EDITOR)\n        table_content = ProseMirrorModelField(**TABLE_EDITOR)\n\nDefault Values\n--------------\n\nAlways use callables for default values returning valid ProseMirror documents:\n\n.. code-block:: python\n\n    class Article(models.Model):\n        # \u2705 Correct: Using a callable\n        content = ProseMirrorModelField(\n            default=lambda: {\"type\": \"doc\", \"content\": []}\n        )\n\n        # \u274c Wrong: Static dict (validation error)\n        # content = ProseMirrorModelField(\n        #     default={\"type\": \"doc\", \"content\": []}\n        # )\n\nDjango Admin Integration\n------------------------\n\nThe field works automatically with Django admin:\n\n.. code-block:: python\n\n    from django.contrib import admin\n    from .models import BlogPost\n\n    @admin.register(BlogPost)\n    class BlogPostAdmin(admin.ModelAdmin):\n        fields = ['title', 'content', 'summary']\n        readonly_fields = ['summary']  # Read-only fields render as HTML\n\n        # Editable fields: Render the full ProseMirror rich-text editor\n        # Read-only fields: Render as formatted HTML output\n\n\nFrontend Integration\n--------------------\n\n**Required Assets**: The ProseMirror form fields require both CSS and JavaScript assets to function. These assets are **mandatory** for any template that renders ProseMirror form fields - without them, the rich text editor will not work.\n\n.. code-block:: html\n\n    {% load django_prosemirror %}\n    <!DOCTYPE html>\n    <html>\n    <head>\n        {% include_django_prosemirror_css %}\n        {% include_django_prosemirror_js_defer %}\n    </head>\n    <body>\n        {{ form.as_p }}\n    </body>\n    </html>\n\n**Note**: These assets are only required for form rendering (editing). Displaying saved content using ``{{ post.content.html }}`` in templates does not require these assets.\n\nAdvanced Usage\n==============\n\nProgrammatic Content Creation\n-----------------------------\n\nCreate ProseMirror content programmatically:\n\n.. code-block:: python\n\n    # Create a document with heading and paragraph\n    content = {\n        \"type\": \"doc\",\n        \"content\": [\n            {\n                \"type\": \"heading\",\n                \"attrs\": {\"level\": 1},\n                \"content\": [{\"type\": \"text\", \"text\": \"My Heading\"}]\n            },\n            {\n                \"type\": \"paragraph\",\n                \"content\": [\n                    {\"type\": \"text\", \"text\": \"Some \"},\n                    {\n                        \"type\": \"text\",\n                        \"marks\": [{\"type\": \"strong\"}],\n                        \"text\": \"bold\"\n                    },\n                    {\"type\": \"text\", \"text\": \" text.\"}\n                ]\n            }\n        ]\n    }\n\n    article = Article.objects.create(content=content)\n\n\nLocal development\n=================\n\nRequirements for development:\n\n* Node.js (for building frontend assets)\n* All runtime requirements listed above\n\nSetup for development:\n\n.. code-block:: bash\n\n    python -mvirtualenv .venv\n    source .venv/bin/activate\n\n    # Install Python package in development mode\n    pip install -e .[tests,coverage,docs,release]\n\n    # Install Node.js dependencies\n    npm install\n\n    # Build frontend assets (when making changes to JavaScript)\n    ./build.sh\n\nWhen running management commands via ``django-admin``, make sure to add the root\ndirectory to the python path (or use ``python -m django <command>``):\n\n.. code-block:: bash\n\n    export PYTHONPATH=. DJANGO_SETTINGS_MODULE=testapp.settings\n    django-admin migrate\n    django-admin createsuperuser  # optional\n    django-admin runserver\n\n\n.. |build-status| image:: https://github.com/maykinmedia/django_prosemirror/workflows/Run%20CI/badge.svg\n    :alt: Build status\n    :target: https://github.com/maykinmedia/django_prosemirror/actions?query=workflow%3A%22Run+CI%22\n\n.. |code-quality| image:: https://github.com/maykinmedia/django_prosemirror/workflows/Code%20quality%20checks/badge.svg\n     :alt: Code quality checks\n     :target: https://github.com/maykinmedia/django_prosemirror/actions?query=workflow%3A%22Code+quality+checks%22\n\n.. |ruff| image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json\n    :target: https://github.com/astral-sh/ruff\n    :alt: Ruff\n\n.. |coverage| image:: https://codecov.io/gh/maykinmedia/django_prosemirror/branch/main/graph/badge.svg\n    :target: https://codecov.io/gh/maykinmedia/django_prosemirror\n    :alt: Coverage status\n\n.. |docs| image:: https://readthedocs.org/projects/django_prosemirror/badge/?version=latest\n    :target: https://django_prosemirror.readthedocs.io/en/latest/?badge=latest\n    :alt: Documentation Status\n\n.. |python-versions| image:: https://img.shields.io/pypi/pyversions/maykin-django-prosemirror.svg\n\n.. |django-versions| image:: https://img.shields.io/pypi/djversions/maykin-django-prosemirror.svg\n\n.. |pypi-version| image:: https://img.shields.io/pypi/v/maykin-django-prosemirror.svg\n    :target: https://pypi.org/project/maykin-django-prosemirror/\n",
    "bugtrack_url": null,
    "license": "Copyright 2025 Maykin Media\n        \n        Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n        \n        The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n        \n        THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n        ",
    "summary": "Rich-text fields for Django using Prosemirror - a powerful, schema-driven rich text editor.",
    "version": "0.2.0",
    "project_urls": {
        "Bug Tracker": "https://github.com/maykinmedia/django-prosemirror/issues",
        "Documentation": "http://django-prosemirror.readthedocs.io/en/latest/",
        "Homepage": "https://github.com/maykinmedia/django-prosemirror",
        "Source Code": "https://github.com/maykinmedia/django-prosemirror"
    },
    "split_keywords": [
        "django",
        " prosemirror",
        " rich-text",
        " editor",
        " document",
        " json",
        " wysiwyg",
        " content editor",
        " text editor",
        " markdown",
        " html"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "fb77924f807aa6774fbce0d28884ad83089f3fb30a7a3055877fdcda62af110f",
                "md5": "aa2df63c45b9863db3dddadc43ee77d4",
                "sha256": "df43a24fcfa5471aedf1cf2baf507cabb530aaddf83529671d98d79caeea49c3"
            },
            "downloads": -1,
            "filename": "maykin_django_prosemirror-0.2.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "aa2df63c45b9863db3dddadc43ee77d4",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.11",
            "size": 151284,
            "upload_time": "2025-10-14T08:34:36",
            "upload_time_iso_8601": "2025-10-14T08:34:36.826798Z",
            "url": "https://files.pythonhosted.org/packages/fb/77/924f807aa6774fbce0d28884ad83089f3fb30a7a3055877fdcda62af110f/maykin_django_prosemirror-0.2.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "e8ca8dafe041d41590e3cc1acc864fe63d7aff29a92d4b9a1e0f0899c011d44c",
                "md5": "a9c5006bb88dea8771a1a6a5b3a25019",
                "sha256": "96c6f28054c809c224efa5439fc650e04f2e93f89c10db40a490661781d2ca52"
            },
            "downloads": -1,
            "filename": "maykin_django_prosemirror-0.2.0.tar.gz",
            "has_sig": false,
            "md5_digest": "a9c5006bb88dea8771a1a6a5b3a25019",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.11",
            "size": 155388,
            "upload_time": "2025-10-14T08:34:38",
            "upload_time_iso_8601": "2025-10-14T08:34:38.172641Z",
            "url": "https://files.pythonhosted.org/packages/e8/ca/8dafe041d41590e3cc1acc864fe63d7aff29a92d4b9a1e0f0899c011d44c/maykin_django_prosemirror-0.2.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-14 08:34:38",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "maykinmedia",
    "github_project": "django-prosemirror",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "tox": true,
    "lcname": "maykin-django-prosemirror"
}
        
Elapsed time: 0.48198s