Migrating from Django admin¶
You don't have to choose between Django admin and Conjure. They coexist on the same permissions, so you can run both, migrate gradually, and keep Django admin as a fallback.
Shared permissions¶
The headline: both admins read the same Group / Permission / is_staff data. There
is no second permission system to keep in sync.
graph TD
P["Group / Permission / is_staff<br/>(single source of truth)"]
P --> DA["Django admin<br/>/django-admin/ (fallback)"]
P --> CW["Conjure web app<br/>/admin-panel/ (primary)"]
Manage permissions in one place (the Django admin Group editor) and both surfaces honour them.
What's shared and what isn't¶
| Concern | Behaviour |
|---|---|
| Permission source | Shared — same Group / Permission. Manage once. |
| CRUD permissions | Shared view / add / change / delete. Can't differ per UI (same codename). |
| Staff gate | Both require is_staff. Superusers pass everything in both. |
| Action lists | Not shared — ModelAdmin.actions and Conjure's ADMIN_ACTIONS are independent. |
| Audit log | Conjure's AdminAuditLog records Conjure writes; Django admin's LogEntry is separate. |
CRUD permissions can't diverge per UI
Because both UIs use the same change_order permission, you can't grant change in one
UI and deny it in the other. If you need that, gate access to one UI itself (move Django
admin to a restricted URL or require a dedicated access permission).
A coexistence setup¶
A common arrangement: Conjure as the day-to-day admin, Django admin parked at a different URL as an emergency fallback.
conjure.spa_urls is planned
Runtime SPA bundling and the conjure.spa_urls mount are on the roadmap, not shipped in
0.1.x. For now, build the dashboard from the monorepo source (packages/web) and serve it
yourself; the mount below shows the intended end state.
urlpatterns = [
path("django-admin/", admin.site.urls), # fallback
path("conjure/", include("conjure.urls")), # API
path("admin-panel/", include("conjure.spa_urls")), # primary UI (planned)
]
Moving Django admin from /admin/ to /django-admin/ is a one-line change; unfold's
sidebar and redirects are reverse-based, so nothing else needs editing. Check operator
bookmarks and any admin-redirect middleware before flipping it in production.
Porting your ModelAdmins¶
AdminConfig is intentionally close to ModelAdmin. Most curation ports directly:
ModelAdmin |
AdminConfig |
|---|---|
list_display |
list_display (real model fields; move computed columns to a custom cell) |
search_fields |
search_fields |
list_filter |
list_filter |
ordering |
ordering |
inlines |
inlines = [(Child, "fk_field")] |
has_add/change/delete_permission = False |
is_readonly = True |
exclude |
exclude |
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
list_display = ["name", "price", "is_active"]
search_fields = ["name"]
list_filter = ["is_active"]
from conjure import register, AdminConfig
@register(Product)
class ProductConfig(AdminConfig):
list_display = ["name", "price", "is_active"]
search_fields = ["name"]
list_filter = ["is_active"]
Keep computed columns out of list_display
Django admin lets you put methods in list_display. Conjure introspects real model
fields, so move computed/derived columns to a frontend
custom cell instead.
A gradual path¶
- Install Conjure alongside Django admin (both at their URLs).
- Port
ModelAdmins toadmin_config.pyone app at a time. - Move Django admin to a fallback URL once parity feels right.
- Decommission Django admin per a feature-parity checklist (Excel import/export, drag ordering, any admin-only pages) when you're ready — or keep it forever as a fallback.
FAQ¶
Do I have to remove Django admin?
No. They share permissions and coexist indefinitely; keeping Django admin as an emergency fallback is a valid long-term choice.
Will registering a model in Conjure affect Django admin?
No. admin_config.py and admin.py are independent files; neither touches the other.
Do both admins log the same activity?
No. Conjure writes AdminAuditLog; Django admin writes LogEntry. They're separate
histories.