Django Unfold admin integration for django-fobi
Project description
django-unfold-fobi
Unfold integration for django-fobi: Unfold-styled admin, Unfold theme for the
form builder UI, DRF compatibility shims, and a few Unfold-friendly admin views.
The optional Sites extension lives in unfold_fobi.contrib.sites.
This README shows the integration steps as they are used in
djangocms_test/settings.py and djangocms_test/urls.py.
Quick Start
- Install dependencies.
pip install django-unfold-fobi
- Follow the standard
django-fobiinstallation and plugin setup first, then add theunfold_fobiintegration apps toINSTALLED_APPS(order matters).
INSTALLED_APPS = [
"unfold", # must be before django.contrib.admin
"crispy_forms", # required by unfold_fobi layouts/templates
"fobi.contrib.themes.simple", # required, Unfold theme extends it
"unfold_fobi",
]
Add your normal django-fobi apps, plugins, and optional DRF integration exactly as documented by django-fobi.
If you want site-aware form bindings, add the optional app too:
INSTALLED_APPS += [
"django.contrib.sites",
"unfold_fobi.contrib.sites",
]
SITE_ID = 1
- Add template context processors and builtins.
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.request",
"fobi.context_processors.theme",
"unfold_fobi.context_processors.admin_site",
],
"builtins": [
"unfold_fobi.templatetags.unfold_fobi_tags",
],
},
},
]
- Enable the Unfold Fobi theme and crispy forms pack.
FOBI_THEME = "unfold"
FOBI_DEFAULT_THEME = "unfold"
CRISPY_TEMPLATE_PACK = "unfold_crispy"
CRISPY_ALLOWED_TEMPLATE_PACKS = ["unfold_crispy"]
- Add URLs from
djangocms_test/urls.py.
from django.urls import include, path
urlpatterns = [
# DRF integration endpoints (optional)
path("api/", include("fobi.contrib.apps.drf_integration.urls")),
path("api/", include("unfold_fobi.api.urls")),
# Public Fobi routes
path("fobi/", include("unfold_fobi.urls.public")),
# Admin/Fobi edit + legacy compatibility routes
# Place before admin.site.urls to avoid admin catch_all_view shadowing.
path("admin/fobi/", include("unfold_fobi.urls.admin")),
]
- Run migrations.
python manage.py migrate
Settings Reference (Unfold Sidebar)
This is the "Forms" navigation block used in djangocms_test/settings.py.
It links to unfold_fobi admin views and Fobi routes. Include the
reverse_lazy/gettext_lazy imports.
from django.urls import reverse_lazy
from django.utils.translation import gettext_lazy as _
UNFOLD = {
"SIDEBAR": {
"navigation": [
{
"title": _("Forms"),
"separator": True,
"collapsible": True,
"items": [
{
"title": _("All Forms"),
"icon": "list",
"link": reverse_lazy("admin:unfold_fobi_formentryproxy_changelist"),
"active": lambda request: (
getattr(getattr(request, "resolver_match", None), "view_name", "")
in {
"admin:unfold_fobi_formentryproxy_changelist",
"admin:unfold_fobi_formentryproxy_add",
"admin:unfold_fobi_formentryproxy_change",
"fobi.edit_form_entry",
}
or request.path.startswith("/admin/unfold_fobi/formentryproxy/")
or request.path.startswith("/admin/fobi/forms/")
),
},
{
"title": _("Import Form"),
"icon": "upload",
"link": reverse_lazy("admin:unfold_fobi_formentryproxy_import_form_entry_action"),
"active": lambda request: getattr(
getattr(request, "resolver_match", None), "view_name", ""
)
in {
"admin:unfold_fobi_formentryproxy_import_form_entry_action",
"fobi.import_form_entry",
}
or request.path.startswith("/admin/fobi/forms/import/")
or request.path.startswith("/admin/unfold_fobi/formentryproxy/import-json/"),
},
{
"title": _("Wizards"),
"icon": "auto_awesome",
"link": reverse_lazy("fobi.form_wizards_dashboard"),
"active": lambda request: getattr(
getattr(request, "resolver_match", None), "view_name", ""
)
in {
"fobi.form_wizards_dashboard",
}
or request.path.startswith("/admin/fobi/wizards/")
},
],
},
],
},
}
Optional Sites Integration
The base package does not require django.contrib.sites. Enable the Sites
extension only if your project needs form-to-site bindings.
- Add the optional apps:
INSTALLED_APPS += [
"django.contrib.sites",
"unfold_fobi.contrib.sites",
]
SITE_ID = 1
UNFOLD_FOBI_SITES_FOR_USER = "myproject.site_permissions.sites_for_user"
- Run migrations:
python manage.py migrate
- Re-register your admin classes with the mixins from
unfold_fobi.contrib.sites.admin:
from django.contrib import admin
from fobi.contrib.plugins.form_handlers.db_store.models import SavedFormDataEntry
from unfold_fobi.admin import FormEntryProxyAdmin as BaseFormEntryProxyAdmin
from unfold_fobi.contrib.sites.admin import (
RelationSiteScopeAdminMixin,
SiteAwareFormEntryMixin,
)
from unfold_fobi.fobi_admin import SavedFormDataEntryAdmin as BaseSavedEntryAdmin
from unfold_fobi.models import FormEntryProxy
admin.site.unregister(FormEntryProxy)
@admin.register(FormEntryProxy)
class FormEntryProxyAdmin(
SiteAwareFormEntryMixin,
RelationSiteScopeAdminMixin,
BaseFormEntryProxyAdmin,
):
site_relation_lookup = "site_binding__sites"
def has_view_permission(self, request, obj=None):
return self._has_site_scoped_permission(request, "view", obj)
def has_change_permission(self, request, obj=None):
return self._has_site_scoped_permission(request, "change", obj)
def has_delete_permission(self, request, obj=None):
return self._has_site_scoped_permission(request, "delete", obj)
admin.site.unregister(SavedFormDataEntry)
@admin.register(SavedFormDataEntry)
class SavedFormDataEntryAdmin(RelationSiteScopeAdminMixin, BaseSavedEntryAdmin):
site_relation_lookup = "form_entry__site_binding__sites"
def has_view_permission(self, request, obj=None):
return self._has_site_scoped_permission(request, "view", obj)
What the package provides:
FobiFormSiteBindingto persist form-to-site relations.SiteAwareFormEntryMixinto add the syntheticsitesfield to the form admin.RelationSiteScopeAdminMixinto filter querysets by a relation path such assite_binding__sitesorform_entry__site_binding__sites.- Binding helpers in
unfold_fobi.contrib.sites.services.
What stays in the consuming project:
- Mapping users to allowed sites.
- Any fallback/default assignment logic when no sites are selected.
- Project-specific
has_*_permission()policy. - Project-specific clone/import wiring beyond the provided binding helpers.
Development & Testing
Prerequisites
Install Poetry for dependency management.
Setup
# Install all dependencies (runtime + dev)
poetry install
# Run database migrations for the test server
poetry run python tests/server/manage.py migrate
Running Tests
# Run the full pytest suite
poetry run pytest -q
# Run with verbose output
poetry run pytest -v
# Run a specific test file
poetry run pytest tests/test_smoke.py -v
Manual Test Server
A local Django test server is included for visual inspection and manual testing.
# Apply migrations (creates tests/server/db.sqlite3)
poetry run python tests/server/manage.py migrate
# Create a superuser for admin login
poetry run python tests/server/manage.py createsuperuser
# Optionally seed a test form with sample fields
poetry run python tests/server/manage.py create_test_form
# Start the server
poetry run python tests/server/manage.py runserver 8080
Then open:
- Admin: http://localhost:8080/admin/
- Add form: http://localhost:8080/admin/unfold_fobi/formentryproxy/add/
- Edit form: http://localhost:8080/admin/unfold_fobi/formentryproxy/edit/1/ (after creating a form)
Test Server Structure
tests/
├── conftest.py # Shared fixtures (admin_user, form_entry)
├── test_smoke.py # Smoke tests (setup, URLs, views, seed data)
├── e2e/ # Playwright browser tests (T04)
│ ├── conftest.py # Browser fixtures (admin_login)
│ └── test_placeholder.py # Scaffold placeholder
└── server/
├── manage.py # Django management entry point
├── db.sqlite3 # SQLite DB (created by migrate, gitignored)
└── testapp/
├── settings.py # Full Unfold + Fobi + unfold_fobi config
├── urls.py # Admin + Fobi + DRF URL wiring
├── wsgi.py
└── asgi.py
Notes
unfold_fobi.apps.UnfoldFobiConfig.ready()automatically loads the DRF compatibility shim and re-registers Fobi admin classes with Unfold, so you do not need manual imports.- The Unfold Fobi theme is registered as
uid="unfold"inunfold_fobi/fobi_themes.py. - If you are using DRF integration, ensure the
db_storehandler is enabled for a form so REST submissions are stored. New forms get it automatically, but existing ones may need the handler attached.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_unfold_fobi-0.1.2.tar.gz.
File metadata
- Download URL: django_unfold_fobi-0.1.2.tar.gz
- Upload date:
- Size: 10.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: python-httpx/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
49aaa0bd770613fa21330e217fe7251648d302547ce82ee445e1d57b6fb1cf74
|
|
| MD5 |
2b8454df1384560d47a704ae066c7dda
|
|
| BLAKE2b-256 |
1514efea41dcb7e8747bbb3b79fa93036a5c3492f616f686237cf301c4ac82e2
|
File details
Details for the file django_unfold_fobi-0.1.2-py3-none-any.whl.
File metadata
- Download URL: django_unfold_fobi-0.1.2-py3-none-any.whl
- Upload date:
- Size: 66.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: python-httpx/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
76505cc3ebdbb13e5b9fbdc5337bc30a27494f395a4196298c1b19fa1d3bb924
|
|
| MD5 |
b5bd09836dd18dec63595164e5061ea3
|
|
| BLAKE2b-256 |
0e58834650c52e3567d4800e61984748e17c1fa64147d950c41925eb66b9ec8f
|