# Quickstart ```{admonition} Quickstart We are making updates quite quickly so the quickstart may get out of sync. Please [create an issue](https://github.com/Dunwright-dev/django-blocknote/issues) if something is incorrect. ``` ## Overview This guide walks you through setting up the Django BlockNote custom field in your Django project. Django BlockNote provides a rich text editor with block-based content editing capabilities, complete with customizable options for different user types and use cases. ## Prerequisites - Django 4.2 or higher - Python 3.8 or higher - Basic understanding of Django models, forms, and views ## Installation ### Step 1: Install the Package ```bash pip install django-blocknote ``` ### Step 2: Add to Django Settings Add `django_blocknote` to your `INSTALLED_APPS`: ```python # settings.py INSTALLED_APPS = [ # ... your other apps 'django_blocknote', ] ``` ### Step 3: Run Migrations ```bash python manage.py migrate ``` ### Step 4: Include URLs Add the django_blocknote URLs to your project's URL configuration: ```python # urls.py from django.urls import include, path urlpatterns = [ # ... your other URLs path('django-blocknote/', include('django_blocknote.urls')), ] ``` This provides the default image upload and removal endpoints. If you configure custom `uploadUrl` or `removalUrl` values in your field config, you can skip this step for those specific endpoints. ## Data Format BlockNote stores content as a JSON array of block objects. A simple document looks like this: ```json [ { "id": "abc123", "type": "heading", "props": {"level": 1}, "content": [{"type": "text", "text": "Hello World"}], "children": [] }, { "id": "def456", "type": "paragraph", "props": {}, "content": [{"type": "text", "text": "This is a paragraph."}], "children": [] } ] ``` This is what gets saved to your database field and what you'll see if you inspect the field value in the Django shell or admin. ## Basic Field Setup ### Import the Field ```python from django_blocknote.models.fields import BlockNoteField ``` ### Add to Your Model Here's a simple example for a blog post model: ```python from django.db import models from django_blocknote.models.fields import BlockNoteField class BlogPost(models.Model): title = models.CharField(max_length=200) content = BlockNoteField( help_text="Main content of the blog post", blank=True, editor_config={ 'placeholder': 'Write your blog post content here...', 'theme': 'light', 'animations': True, }, image_upload_config={ 'img_model': 'blog:BlogPost', # app_label:ModelName format 'maxFileSize': 10 * 1024 * 1024, # 10MB 'allowedTypes': ['image/*'] }, image_removal_config={ 'removalUrl': '/django-blocknote/remove-image/', 'retryAttempts': 3, }, menu_type='admin', ) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) ``` The `img_model` value uses `app_label:ModelName` format, matching your Django app's label (from `AppConfig.label` or the last segment of the dotted app path) and the model class name. ## Configuration Options ### Editor Configuration The `editor_config` parameter accepts the following options: ```python editor_config = { 'placeholder': 'Start writing...', # Placeholder text 'theme': 'light', # 'light' or 'dark' 'animations': True, # Enable/disable animations 'editable': True, # Make editor readonly if False 'collaboration': False, # Enable collaboration features } ``` ### Image Upload Configuration Configure image handling with `image_upload_config`: ```python image_upload_config = { 'img_model': 'app:Model', # Django model reference 'maxFileSize': 10 * 1024 * 1024, # Maximum file size (10MB) 'allowedTypes': ['image/*'], # Allowed MIME types 'uploadUrl': '/custom-upload-url/', # Custom upload endpoint 'showProgress': True, # Show upload progress 'maxConcurrent': 3, # Max concurrent uploads 'autoResize': True, # Auto-resize large images 'maxWidth': 1920, # Max width for resized images 'maxHeight': 1080, # Max height for resized images 'quality': 85, # JPEG quality (1-100) } ``` ### Image Removal Configuration Handle image deletion with `image_removal_config`: ```python image_removal_config = { 'removalUrl': '/django-blocknote/remove-image/', # Removal endpoint 'retryAttempts': 3, # Retry attempts on failure 'timeout': 30000, # Timeout in milliseconds } ``` ### Menu Type Configuration The `menu_type` parameter controls which slash menu configuration to use. Menu types are defined in your Django settings via `DJ_BN_SLASH_MENU_CONFIGS`. The widget looks up the specified `menu_type` key in this dictionary: ```python # settings.py DJ_BN_SLASH_MENU_CONFIGS = { '_default': { 'enabled': False, }, 'admin': { 'enabled': True, 'mode': 'default', }, 'blog': { 'enabled': True, 'mode': 'filtered', 'disabled_items': ['video', 'audio', 'file'], }, 'documentation': { 'enabled': True, 'mode': 'filtered', 'disabled_items': ['image', 'video', 'audio'], }, } ``` If the specified `menu_type` is not found in `DJ_BN_SLASH_MENU_CONFIGS`, the `_default` configuration is used as a fallback. A warning will appear in the server logs when this happens. Use the `menu_type` in your field definition: ```python # Example configurations content = BlockNoteField(menu_type='default') # Regular users content = BlockNoteField(menu_type='admin') # Administrators content = BlockNoteField(menu_type='blog') # Blog posts ``` ## Setting Up Forms and Views ### Form Configuration Use the provided mixins to handle user context and widget configuration: ```python from django import forms from django_blocknote.mixins import BlockNoteModelFormMixin class BlogPostForm(BlockNoteModelFormMixin): class Meta: model = BlogPost fields = ['title', 'content'] ``` ### View Configuration Use the view mixin to automatically pass user context: ```python from django.views.generic import CreateView, UpdateView from django_blocknote.views.mixins import BlockNoteViewMixin class BlogPostCreateView(BlockNoteViewMixin, CreateView): model = BlogPost form_class = BlogPostForm template_name = 'blog/create_post.html' class BlogPostUpdateView(BlockNoteViewMixin, UpdateView): model = BlogPost form_class = BlogPostForm template_name = 'blog/update_post.html' ``` ### Template Setup Include the form's media files in your template. This loads the BlockNote editor JavaScript and CSS: ```html {% block extra_head %} {{ form.media }} {% endblock %}
``` Without `{{ form.media }}`, the editor will not render and you'll see the raw textarea fallback instead. ### Displaying Content (Readonly Mode) To render saved BlockNote content in a read-only view, use the widget's readonly mode in your form: ```python from django_blocknote.widgets import BlockNoteWidget class BlogPostDisplayForm(BlockNoteModelFormMixin): class Meta: model = BlogPost fields = ['content'] widgets = { 'content': BlockNoteWidget(mode='readonly'), } ``` This renders the editor without editing controls, toolbars, or the slash menu — suitable for public-facing pages. ## Architecture Overview ```{mermaid} graph TD A[Django Model] --> B[BlockNoteField] B --> C[BlockNoteWidget] C --> D[Frontend Editor] E[User Request] --> F[View with BlockNoteViewMixin] F --> G[Form with BlockNoteModelFormMixin] G --> C D --> H[Image Upload Handler] D --> I[Content Serialization] H --> J[Image Storage] I --> K[Database Storage] L[App Configuration] --> M[Settings & Defaults] M --> N[Slash Menu Config] M --> O[Image Handling Config] M --> P[Editor Theme Config] ``` ## Configuration Flow ```{mermaid} sequenceDiagram participant App as Django App participant Config as AppConfig participant Settings as Django Settings participant Field as BlockNoteField participant Widget as BlockNoteWidget App->>Config: App startup Config->>Settings: Configure defaults Settings->>Settings: Merge user settings Field->>Settings: Read configuration Field->>Widget: Initialize with config Widget->>Widget: Render editor with settings ``` ## External Content Updates BlockNote editors sync content to a hidden `