# How to Add Template Management to Your Project This guide shows you how to implement user template management in your Django project using Django BlockNote's `DocumentTemplate` model. ## What You'll Build By the end of this guide, you'll have: - Template creation and editing forms - User-specific template listing - Template deletion functionality - Automatic cache management ## Prerequisites - Django BlockNote installed and configured - Basic familiarity with Django class-based views - A Django project with user authentication ## Step 1: Create Your Forms Create a form that inherits from Django BlockNote's form mixins to handle template creation and editing. ```python # forms.py from django import forms from django_blocknote.models import DocumentTemplate from django_blocknote.mixins import BlockNoteModelFormMixin from django_blocknote.widgets import BlockNoteWidget class DocumentTemplateForm(BlockNoteModelFormMixin): class Meta: model = DocumentTemplate fields = ['title', 'subtext', 'aliases', 'group', 'icon', 'content', 'show_in_menu'] widgets = { 'content': BlockNoteWidget(), 'subtext': forms.TextInput(attrs={'maxlength': 20}), 'aliases': forms.TextInput(attrs={ 'placeholder': 'meeting, notes, agenda', 'help_text': 'Enter comma-separated search terms' }), } def clean_title(self): """Ensure unique titles per user""" title = self.cleaned_data['title'] # Check for duplicate titles for this user if DocumentTemplate.objects.filter( user=self.user, title=title ).exclude(pk=self.instance.pk if self.instance.pk else None).exists(): raise forms.ValidationError("You already have a template with this title.") return title ``` ## Step 2: Create Your Views Set up views for template management using Django BlockNote's view mixins. ```python # views.py from django.contrib.auth.mixins import LoginRequiredMixin from django.views.generic import CreateView, UpdateView, DeleteView, ListView from django.urls import reverse_lazy from django.contrib import messages from django_blocknote.models import DocumentTemplate from django_blocknote.views.mixins import BlockNoteViewMixin from .forms import DocumentTemplateForm class TemplateListView(LoginRequiredMixin, ListView): """Display user's templates""" model = DocumentTemplate template_name = 'templates/template_list.html' context_object_name = 'templates' paginate_by = 10 def get_queryset(self): """Only show current user's templates""" return DocumentTemplate.objects.filter( user=self.request.user ).order_by('group', 'title') class TemplateCreateView(LoginRequiredMixin, BlockNoteViewMixin, CreateView): """Create a new template""" model = DocumentTemplate form_class = DocumentTemplateForm template_name = 'templates/template_form.html' success_url = reverse_lazy('template-list') def form_valid(self, form): """Set the user before saving""" form.instance.user = self.request.user messages.success(self.request, f"Template '{form.instance.title}' created successfully!") return super().form_valid(form) class TemplateUpdateView(LoginRequiredMixin, BlockNoteViewMixin, UpdateView): """Edit an existing template""" model = DocumentTemplate form_class = DocumentTemplateForm template_name = 'templates/template_form.html' success_url = reverse_lazy('template-list') def get_queryset(self): """Users can only edit their own templates""" return DocumentTemplate.objects.filter(user=self.request.user) def form_valid(self, form): messages.success(self.request, f"Template '{form.instance.title}' updated successfully!") return super().form_valid(form) class TemplateDeleteView(LoginRequiredMixin, DeleteView): """Delete a template""" model = DocumentTemplate template_name = 'templates/template_confirm_delete.html' success_url = reverse_lazy('template-list') def get_queryset(self): """Users can only delete their own templates""" return DocumentTemplate.objects.filter(user=self.request.user) def delete(self, request, *args, **kwargs): template = self.get_object() messages.success(request, f"Template '{template.title}' deleted successfully!") return super().delete(request, *args, **kwargs) ``` ## Step 3: Configure URLs Add URL patterns for your template views. ```python # urls.py from django.urls import path from . import views app_name = 'templates' urlpatterns = [ path('', views.TemplateListView.as_view(), name='template-list'), path('create/', views.TemplateCreateView.as_view(), name='template-create'), path('/edit/', views.TemplateUpdateView.as_view(), name='template-edit'), path('/delete/', views.TemplateDeleteView.as_view(), name='template-delete'), ] ``` ## Step 4: Create Templates ### Template List (`templates/template_list.html`) ```html {% extends 'base.html' %} {% load static %} {% block title %}My Templates{% endblock %} {% block content %}

My Templates

Create Template
{% if templates %}
{% for template in templates %}
{% if template.icon == 'meeting' %}📅 {% elif template.icon == 'document' %}📄 {% elif template.icon == 'checklist' %}✅ {% else %}📝{% endif %}

{{ template.title }}

{% if template.subtext %}

{{ template.subtext }}

{% endif %} {% if template.group %} {{ template.group }} {% endif %}
{% if template.show_in_menu %} ✓ Visible in menu {% else %} Hidden from menu {% endif %}
{% endfor %}
{% if is_paginated %}
{% if page_obj.has_previous %} Previous {% endif %} Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }} {% if page_obj.has_next %} Next {% endif %}
{% endif %} {% else %}

No templates yet

Create your first template to get started.

Create Your First Template
{% endif %}
{% endblock %} ``` ### Template Form (`templates/template_form.html`) ```html {% extends 'base.html' %} {% load static %} {% block title %} {% if object %}Edit Template{% else %}Create Template{% endif %} {% endblock %} {% block content %}

{% if object %}Edit Template: {{ object.title }}{% else %}Create New Template{% endif %}

{% csrf_token %}
{{ form.title }} {% if form.title.errors %}

{{ form.title.errors.0 }}

{% endif %}
{{ form.subtext }} {% if form.subtext.errors %}

{{ form.subtext.errors.0 }}

{% endif %}
{{ form.group }}

Organize templates by category

{{ form.icon }}
{{ form.aliases }}

Comma-separated search terms (e.g., "meeting, notes, agenda")

{% if form.aliases.errors %}

{{ form.aliases.errors.0 }}

{% endif %}
{{ form.content }} {% if form.content.errors %}

{{ form.content.errors.0 }}

{% endif %}
Cancel
{% endblock %} ``` ### Delete Confirmation (`templates/template_confirm_delete.html`) ```html {% extends 'base.html' %} {% block title %}Delete Template{% endblock %} {% block content %}

Delete Template

Are you sure you want to delete "{{ object.title }}"?

This action cannot be undone. The template will be permanently removed from your account and will no longer appear in the BlockNote menu.

{% if object.subtext %}

Description: {{ object.subtext }}

{% endif %} {% if object.group %}

Group: {{ object.group }}

{% endif %}
{% csrf_token %} Cancel
{% endblock %} ``` ## Step 5: Add Navigation Links Add links to your template management in your base template or navigation. ```html My Templates ``` ## Implementation Flow ```{mermaid} graph TD A[User visits template list] --> B[TemplateListView] B --> C[Filter by current user] C --> D[Display templates] E[User clicks Create] --> F[TemplateCreateView] F --> G[BlockNoteViewMixin injects user] G --> H[DocumentTemplateForm] H --> I[clean_aliases converts CSV to JSON] I --> J[Save template with user] J --> K[Cache automatically refreshed] L[User clicks Edit] --> M[TemplateUpdateView] M --> N[Check ownership] N --> O[Pre-populate form] O --> P[Save changes] P --> K Q[User clicks Delete] --> R[TemplateDeleteView] R --> S[Check ownership] S --> T[Confirm deletion] T --> U[Delete template] U --> K style K fill:#c8e6c9 style G fill:#fff3e0 style I fill:#e3f2fd ``` ## What Happens Behind the Scenes 1. **Form Processing**: The `BlockNoteViewMixin` automatically injects the current user into forms 2. **Alias Conversion**: The `clean_aliases()` method converts CSV input to JSON strings for efficient storage 3. **Cache Management**: Django BlockNote automatically refreshes the user's template cache when templates are saved or deleted 4. **Security**: Views automatically filter templates by the current user to prevent unauthorized access ## Testing Your Implementation 1. **Create a template**: Visit `/templates/create/` and fill out the form 2. **Check the menu**: The template should appear in BlockNote's slash menu 3. **Edit templates**: Click edit from the template list 4. **Delete templates**: Use the delete confirmation flow 5. **Test aliases**: Add comma-separated aliases and verify they work in the slash menu search ## Next Steps - Add template categories with custom icons - Implement template sharing between users - Add template import/export functionality - Create template usage analytics Your users can now create, edit, and manage their own BlockNote templates with automatic cache management and a clean, intuitive interface!