Skip to main content

Django Unfold admin integration for django-fobi

Project description

django-unfold-fobi

PyPI - Version Build

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

  1. Install dependencies.
pip install django-unfold-fobi
  1. Follow the standard django-fobi installation and plugin setup first, then add the unfold_fobi integration apps to INSTALLED_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
  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",
            ],
        },
    },
]
  1. 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"]
  1. 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")),
]
  1. 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.

  1. 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"
  1. Run migrations:
python manage.py migrate
  1. 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:

  • FobiFormSiteBinding to persist form-to-site relations.
  • SiteAwareFormEntryMixin to add the synthetic sites field to the form admin.
  • RelationSiteScopeAdminMixin to filter querysets by a relation path such as site_binding__sites or form_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:

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" in unfold_fobi/fobi_themes.py.
  • If you are using DRF integration, ensure the db_store handler 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_unfold_fobi-0.1.4b0.tar.gz (10.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_unfold_fobi-0.1.4b0-py3-none-any.whl (67.9 kB view details)

Uploaded Python 3

File details

Details for the file django_unfold_fobi-0.1.4b0.tar.gz.

File metadata

  • Download URL: django_unfold_fobi-0.1.4b0.tar.gz
  • Upload date:
  • Size: 10.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-httpx/0.28.1

File hashes

Hashes for django_unfold_fobi-0.1.4b0.tar.gz
Algorithm Hash digest
SHA256 d081b27906a4a5dedb6f3e6e4fcedb36969b5cabac291f1df73475c83291edb5
MD5 48c2a856ee3f71d2c262cac8e03ada73
BLAKE2b-256 f834ac9792f4f2a168d0da86d24d5cfecaada65c057aa2e34c6b910846a07860

See more details on using hashes here.

File details

Details for the file django_unfold_fobi-0.1.4b0-py3-none-any.whl.

File metadata

File hashes

Hashes for django_unfold_fobi-0.1.4b0-py3-none-any.whl
Algorithm Hash digest
SHA256 155cdef9e98efed2f8e4fba8ed0e81065877ca7c3713fc10bfc1e41385f3f13b
MD5 5ed6710bbe17fd7f0f5e59d2008ecef3
BLAKE2b-256 40abefda9fe0fec03d412269a7c41e55ca955fe2ec5ca5c6c619d015c4fb1f22

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page