Migrating from Django¶
HyperDjango is Django-inspired with the same mental model. If you know Django, you know 80% of HyperDjango. This guide covers what's the same, what's different, and what's better.
What's the Same¶
| Concept | Django | HyperDjango |
|---|---|---|
| Models | class Book(models.Model) |
class Book(TimestampMixin, Model) |
| Fields | models.CharField(max_length=100) |
title: str = Field(max_length=100) |
| ORM queries | Book.objects.filter(published=True) |
Book.objects.filter(published=True) |
| Admin | admin.site.register(Book) |
admin.register(Book) |
| Migrations | python manage.py migrate |
uv run hyper setup --app app:app |
| Templates | {% for book in books %} |
{% for book in books %} (Jinja2-compatible) |
| Middleware | MIDDLEWARE = [...] |
app.use(CORSMiddleware(...)) |
| Signals | post_save.connect(handler) |
post_save.connect(handler) |
| Forms | class BookForm(forms.Form) |
class BookForm(Form) |
What's Different¶
Models¶
# Django
class Book(models.Model):
title = models.CharField(max_length=200)
price = models.DecimalField(max_digits=10, decimal_places=2)
published = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
indexes = [models.Index(fields=['title'])]
# HyperDjango — type annotations instead of field classes
class Book(TimestampMixin, Model): # TimestampMixin adds created_at/updated_at
title: str = Field(max_length=200)
price: Decimal = Field(default=Decimal("0.00"))
published: bool = Field(default=False)
class Meta:
indexes = [Index(fields=("title",))]
Key differences:
- Type annotations instead of
models.CharField— the field type comes from the Python type - TimestampMixin provides
created_at/updated_aton every model - No
auto_now_add— timestamps are managed bysave(), not the DB Field()for metadata (max_length, default, primary_key, foreign_key)
Views/Routes¶
# Django
# urls.py
urlpatterns = [path('books/', views.book_list)]
# views.py
def book_list(request):
books = Book.objects.filter(published=True)
return JsonResponse({"books": list(books.values())})
# HyperDjango — decorator-based, async by default
@app.get("/books/")
async def book_list(request):
books = await Book.objects.filter(published=True).all()
return Response.json({"books": [b.to_dict() for b in books]})
Key differences:
- Async by default — all handlers are
async def - Decorator routing —
@app.get("/path/")instead ofurls.py - Path params —
@app.get("/books/{id:int}")with type coercion awaiton all DB operations
Auth¶
# Django
from django.contrib.auth.decorators import login_required
@login_required
def my_view(request): ...
# HyperDjango — guard system with RBAC
from hyperdjango import guard, Require
@app.get("/admin/dashboard")
@guard(Require.authenticated(), Require.role("admin"))
async def admin_dashboard(request): ...
Key differences:
- RBAC groups instead of
is_staffbooleans —Require.role("admin") - SessionUser with
frozenset[str]groups/permissions — O(1) membership checks build_session_data()at login populates session with RBAC groups- Guard composition —
Require.any_of(Require.role("admin"), Require.api_key())
Admin¶
# Django
class BookAdmin(admin.ModelAdmin):
list_display = ['title', 'price', 'published']
search_fields = ['title']
admin.site.register(Book, BookAdmin)
# HyperDjango — single call, same options
admin.register(Book,
list_display=["title", "price", "published"],
search_fields=["title"],
list_filter=["published"],
)
The admin is built-in with no separate Django dependency. It auto-generates CRUD, search, filters, FK dropdowns, inline editing, and RBAC management tools.
REST API¶
# Django REST Framework
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
# HyperDjango — same pattern, built-in
class BookSerializer(ModelSerializer):
class Meta:
model = Book
class BookViewSet(ModelViewSet):
model = Book
serializer_class = BookSerializer
router = APIRouter(prefix="/api/v1")
router.register("books", BookViewSet)
router.mount(app)
What's Better¶
| Feature | Django | HyperDjango |
|---|---|---|
| Database | psycopg3 (Python) | pg.zig (native, 2-42x faster) |
| HTTP Server | uvicorn/gunicorn | Native Zig (2.1x faster) |
| Templates | Django templates | Zig compiled (234x faster compile, 1.7x render) |
| JSON | stdlib json | SIMD Zig (6-10x faster) |
| Validation | Python | SIMD Zig (13M models/sec) |
| Threading | GIL-limited | Free-threaded Python 3.14t |
| Admin | Separate app | Built-in, zero config |
| RBAC | 3rd-party Django package | Built-in hierarchical RBAC |
| Telemetry | 3rd-party Django package | Built-in Prometheus + spans |
| WebSocket | channels (3rd party) | Built-in native Zig RFC 6455 |
Migration Checklist¶
- Replace
models.ModelwithTimestampMixin, Model - Replace field classes with type annotations +
Field() - Replace
urls.pywith@app.get/@app.postdecorators - Add
awaitto all DB operations - Replace
@login_requiredwith@guard(Require.authenticated()) - Replace
is_staffchecks withRequire.role("staff") - Replace
admin.site.registerwithadmin.register - Run
uv run hyper setup --app app:appto create tables