Lightweight utilities to collect and manage ad-hoc Django/Wagtail form submissions without requiring a form Page type. Provides a small model layer, admin views for browsing submissions, and a helpful Form base class with a submit() helper.
- Store arbitrary Django form submissions in a
FormSubmissionmodel - Small
Formmodel to group submissions by logical label wagtail_forms.forms.Formbase class with asubmit(request=...)convenience method- Wagtail admin integrations for listing, inspecting, exporting and deleting submissions
- Templates for simple submission viewing and index pages (overrideable)
- Python 3.11+
- Django (compatible release for your project)
- Wagtail (compatible release for your project)
- django.contrib.humanize must be added to INSTALLED_APPS in your Django settings (required by package templates)
This project's pyproject.toml specifies requires-python = ">=3.11" — pick Django/Wagtail versions that match your site.
Install from source (editable) for development:
pip install wagtail-formsThen add the app to INSTALLED_APPS in your Django settings:
INSTALLED_APPS = [
# ...
'wagtail_forms',
'django.contrib.humanize',
]Include the URL patterns where appropriate (example for a site urls.py):
from django.urls import include, path
urlpatterns = [
# ...
path('forms/', include('wagtail_forms.urls')),
]Run migrations:
python manage.py migrateCreate a Django form class that subclasses wagtail_forms.forms.Form. When the form is valid call its submit() method with the request to persist a submission and attach metadata (IP, user agent, referer, user):
from django import forms
from wagtail_forms.forms import Form as WagtailForm
class ContactForm(WagtailForm):
name = forms.CharField(max_length=255)
email = forms.EmailField()
message = forms.CharField(widget=forms.Textarea)
# In your view:
def contact_view(request):
form = ContactForm(request.POST or None)
if request.method == 'POST' and form.is_valid():
fm = form.submit(request=request)
# `fm` is or represents the stored `wagtail_forms.models.Form` instance
# you can redirect or render a thanks pageThe submit() helper will create or get a Form record using the class name as the label (or _label if set on the form class) and call the model's processing logic to create a FormSubmission row.
The project exposes models Form and FormSubmission. In the Wagtail admin you get list views and an inspect view for individual submissions. FormSubmission includes helpful properties for:
form_data_humanized— a cleaned representation of stored form dataform_data_json— JSON representation of the submission- parsed user-agent and derived
browser/device locationhelper that attempts to resolve an IP to a city/country (when available)
There are also views and URL helpers to export submissions and delete them in bulk.
Ship templates live under wagtail_forms/templates/wtforms/. You can override these in your project templates directory by providing templates with the same paths. Notable templates:
wtforms/index.html— index/listing viewwtforms/submissions/view.html— single submission inspect view
This project includes an example Wagtail project under the example/ directory you can use to test and develop the library locally.
Recommended steps (PowerShell / cross-platform commands shown):
git clone git@github.com:DazzyMlv/wagtail-forms.git
cd wagtail-formsgit switch -c feat/dev-setupuv venv .venvPowerShell:
.\.venv\Scripts\Activate.ps1POSIX (bash / macOS / Linux):
source .venv/bin/activateInstall the project in editable mode and any example requirements if present:
uv sync --group dev --group test
uv add --dev --editable . # OR pip install -e .
pre-commit installRun migrations and create a superuser:
python manage.py migrate
python manage.py createsuperuserRun with Django's development server:
python manage.py runserver # OR python manage.py runserver_plusOr, if you prefer an ASGI server and the example exposes an ASGI app, you can run with uvicorn (install with pip install uvicorn):
# example: uvicorn example_project.asgi:application --reload --port 8000
uvicorn example.asgi:application --reloadIf you add tests or linters, run them:
# run project tests (if present)
python -m pytest
# run linters (if configured)
flake8 src testsMake small, focused commits. Example workflow:
pre-commit run --all-files
git add -A
git commit -m "core: improve development docs and example setup"
git push -u origin feat/dev-setup
# Open a PR on GitHub to merge into develop/mainNotes
- The
example/folder is intended to make it quick to smoke-test the library inside a minimal Wagtail project. Inspect its README or files for any example-specific setup steps. - Use the editable install (
pip install -e .ORuv add --dev --editable .) so changes tosrc/wagtail_formsare picked up by the running example without reinstalling. - If you prefer Docker for development, you can add a small docker-compose setup that builds an image from this repo and runs the example project; that is not included by default.
Contributions are welcome. Please open an issue to discuss larger changes before sending a pull request. Keep changes focused and include tests where appropriate.
This project is released under the MIT License. See LICENSE for details.
Open issues on the repository for bugs or feature requests.