Theia NG — a dynamic Angular admin for Django, generated from your models.
Project description
Theia NG
A dynamic Angular admin for Django, generated from your models — no build step.
Theia NG brings a django.contrib.admin-style experience to a modern
Angular SPA. You register your models the way you already know, and Theia NG
serves a full CRUD admin introspected from your ORM at runtime. No code
generation on your side, no Node toolchain to install — the compiled Angular app
ships inside the wheel.
ℹ️ Named after Theia, the Titaness of sight. Referred to as Theia NG to avoid confusion with the Eclipse Theia IDE.
Why
- ORM is the source of truth. Theia NG mirrors your Django models, not your API. Like the built-in admin, it ships its own auto-CRUD layer, so it works with any Django project — Django REST Framework is not required.
- No dependency on
django.contrib.admin. It builds ondjango.contrib.authfor permissions and uses the admin only as a design reference. ItsModelAdmin-style registry is its own. - Dynamic, not generated. Models are introspected at runtime and served as a small intermediate representation the SPA consumes. Model changes show up immediately; there is no client-side build.
- One prefix, runtime-configured bundle. The SPA and its API mount under a single configurable prefix; the prebuilt bundle is prefix-independent.
Features
- Auto-CRUD: list with search, filtering, sorting, pagination; create / update / delete; custom server-side actions
ModelAdmin-style config:list_display,list_filter,search_fields,ordering,readonly_fields,actions- Searchable, paginated relation pickers (FK single, M2M multi) that load options on demand — fine for tables with thousands of rows
- Session login built into the SPA, gated by the
theia_ng.accesspermission - Sidebar grouped by Django app; sticky top bar with sign-out
- Optional DRF delegation (use your serializers) and OpenAPI enrichment — both lazy, so the core never imports DRF
Requirements
- Python 3.11+
- Django 4.2 LTS or 5.2 LTS
- Django REST Framework 3.14+ (optional, only for DRF delegation)
Installation
pip install theia_ng
Quickstart
1. Add the app to INSTALLED_APPS:
INSTALLED_APPS = [
# …
"django.contrib.auth",
"theia_ng",
]
2. Mount it under any prefix in your root urls.py:
from django.urls import include, path
urlpatterns = [
path("theia/", include("theia_ng.urls")),
]
3. Register models in an app's theia.py (autodiscovered, like admin.py):
import theia_ng
from myapp.models import Article, Category
@theia_ng.register(Article)
class ArticleAdmin(theia_ng.ModelAdmin):
list_display = ["title", "category", "published", "created"]
list_filter = ["published", "category"]
search_fields = ["title"]
ordering = ["-created"]
readonly_fields = ["created", "modified"]
@theia_ng.register(Category)
class CategoryAdmin(theia_ng.ModelAdmin):
list_display = ["name"]
search_fields = ["name"]
4. Migrate (creates the theia_ng.access permission):
python manage.py migrate
5. Grant access — superusers always pass; otherwise give a user the
theia_ng.access permission (plus the usual per-model view/add/change/delete
permissions). Open …/theia/ and sign in.
Configuration
All optional, via a THEIA_NG dict in settings:
THEIA_NG = {
"SITE_TITLE": "My Admin", # shown in the top bar
"MOUNT_PREFIX": "/theia/", # usually auto-detected from the request
"SCHEMA_TTL": 300, # IR cache TTL in seconds (0 disables caching)
"CACHE_VERSION": "1", # bump to invalidate the IR cache on deploy
}
The introspected schema is cached (structure only; per-user permissions are always computed fresh). Configure a shared cache backend (e.g. Redis) in production so all workers agree.
Permissions & auth
- The SPA uses Django session auth (same origin). It sends the CSRF token as
X-CSRFToken, so keep the defaultcsrftokencookie readable (CSRF_COOKIE_HTTPONLY = False, the Django default). - Entry is gated by the
theia_ng.accesspermission — notis_staff, so it never collides with the Django admin. - Per-model access uses the standard
view/add/change/deletepermissions. Overridehas_*_permission(self, request)on yourModelAdminto plug in a custom scheme.
Dependent relation options
Narrow a relation field's options by the current values of sibling fields on
the record being edited — e.g. only show Spaces that belong to the Stock's
selected house:
@theia_ng.register(Stock)
class StockAdmin(theia_ng.ModelAdmin):
relation_filters = {
"spaces": {"house": "house"}, # {target_lookup: source_field}
}
This loads Space.objects.filter(house=<the form's current house value>). The
picker re-fetches when house changes, and shows nothing until it is set. The
filter lookups are server-defined (the client only sends the sibling
values), so it can't be used to query arbitrary fields.
Optional: DRF delegation
If a model already has a DRF serializer, let Theia NG defer to it for (de)serialization and validation:
@theia_ng.register(Article)
class ArticleAdmin(theia_ng.ModelAdmin):
serializer_class = ArticleSerializer
The serializer also enriches the schema (required / read-only / help text). DRF is imported lazily — if you don't use this, you don't need DRF installed.
License
MIT — see LICENSE.
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
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 theia_ng-0.1.2.tar.gz.
File metadata
- Download URL: theia_ng-0.1.2.tar.gz
- Upload date:
- Size: 150.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
48dd17921a997467479f5d3088990701052f2349b3c3949bcf6ee3273d71cf4c
|
|
| MD5 |
6ba98e17afbba09939e48653afc9b691
|
|
| BLAKE2b-256 |
5e74a16c51a83eb569b87f09c0745945cafab50031674bd3de3f504beb544481
|
Provenance
The following attestation bundles were made for theia_ng-0.1.2.tar.gz:
Publisher:
release.yml on davidsarosi92/theia_ng
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
theia_ng-0.1.2.tar.gz -
Subject digest:
48dd17921a997467479f5d3088990701052f2349b3c3949bcf6ee3273d71cf4c - Sigstore transparency entry: 1788147733
- Sigstore integration time:
-
Permalink:
davidsarosi92/theia_ng@f6c1470f096de83827bbe8120853476e40d131ac -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/davidsarosi92
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@f6c1470f096de83827bbe8120853476e40d131ac -
Trigger Event:
push
-
Statement type:
File details
Details for the file theia_ng-0.1.2-py3-none-any.whl.
File metadata
- Download URL: theia_ng-0.1.2-py3-none-any.whl
- Upload date:
- Size: 124.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
22f63137125d64790f6b418bd7bc9735b2913d07befa757d22d968dad6259802
|
|
| MD5 |
3bbba0b0f91a48758de29dbe32e13656
|
|
| BLAKE2b-256 |
891ad3932dcaaf1b22e66211a06de928ea1bbe6812789665d533b780fb6c422e
|
Provenance
The following attestation bundles were made for theia_ng-0.1.2-py3-none-any.whl:
Publisher:
release.yml on davidsarosi92/theia_ng
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
theia_ng-0.1.2-py3-none-any.whl -
Subject digest:
22f63137125d64790f6b418bd7bc9735b2913d07befa757d22d968dad6259802 - Sigstore transparency entry: 1788147826
- Sigstore integration time:
-
Permalink:
davidsarosi92/theia_ng@f6c1470f096de83827bbe8120853476e40d131ac -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/davidsarosi92
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@f6c1470f096de83827bbe8120853476e40d131ac -
Trigger Event:
push
-
Statement type: