Comparatif

Comparison: Runique vs Django

CLI

CommandDjangoRunique
Create projectdjango-admin startproject namerunique new name
Create apppython manage.py startapp name
Migrations (generate)python manage.py makemigrationsrunique makemigrations
Migrations (apply)python manage.py migraterunique migration up (wrapper for sea-orm-cli migrate up)
Migrations (rollback)python manage.py migrate app 0001runique migration down --files ... (wrapper for sea-orm-cli migrate down)
Migration statusrunique migration status (wrapper for sea-orm-cli migrate status)
Create superuserpython manage.py createsuperuserrunique create-superuser
Start servicespython manage.py runservercargo runrunique start only for first init/admin view generation

Routing

FeatureDjangoRunique
URL Declarationurls.py with path()url.rs with urlpatterns!{} macro
Dynamic Routespath('users/<int:id>/', view)"/users/{id}" in urlpatterns!
Namespacesapp_name + include()Router::new().nest("/prefix", ...)
Reverse URL{% url "view_name" %} native{% link "view_name" %} → custom Tera function
Get Path Paramkwargs['id']form.cleaned_* or request.path_param("id")
Get Query Paramrequest.GET.get('key')form.cleaned_* or request.from_url("key")

Views / Handlers

FeatureDjangoRunique
Function viewdef my_view(request)async fn my_view(...)
Class viewclass MyView(View)
Session accessrequest.sessionrequest.session via context::template::Request
DB accessModel.objects.get(...)Model::objects.get(...) (via impl_objects!) or SeaORM query builders
Template renderrender(request, "template.html", ctx)request.render("template.html") — context already in request.context
Redirectredirect("url_name")Redirect::to("/url") or reverse(&engine, "name") (prelude)
Flash messagesmessages.success(request, "...")success!(message => "...")success!, error!, info!, warning! macros

Forms

FeatureDjangoRunique
Definitionclass MyForm(forms.Form) / class MyForm(ModelForm)#[form] struct (ModelForm equiv) or manual RuniqueForm
Validationform.is_valid()form.is_valid().await
Available FieldsCharField, EmailField, etc.TextField, EmailField, PasswordField, HiddenField, ChoiceField, NumericField, BooleanField, FileField, DateTimeField, DurationField
HTML Rendering{{ form.as_p }}{% form.my_form %} (full) or {% form.my_form.field %} (individual)
CSRF includedautomaticautomatic — injected before the first field
Save to DBform.save()form.save(&db).await (if using #[form])
Data accessform.cleaned_data['key']form.cleaned_*("key") (e.g., string, i32, bool, uuid, etc.)
Async validationnoyes (direct DB access in clean())
File formsFileFieldNative multipart with dimensions/format validation

Templates

FeatureDjangoRunique
EngineDjango Template LanguageTera (Jinja2 / Django-like syntax)
Inheritance{% extends %} / {% block %}same with Tera
Static files{% load static %} {% static "file" %}{% static "file" %} native
Media files{{ MEDIA_URL }}file{% media "file" %} native
URL reverse{% url "name" %}{% link "name" %}
CSRF{% csrf_token %}{% csrf %}
Messages{% for m in messages %}{% messages %}
I18n{% trans "..." %}{{ t("section.key") }} or {{ tf("...", ["var"]) }}

ORM / Database

FeatureDjangoRunique
ORMNative Django ORMSeaORM (Rust async)
Model definitionclass User(models.Model)Rust struct with annotations + model!{} macro
Auto migrationsyes (change detection)runique makemigrations
Chainable QuerySetUser.objects.filter(...).order_by(...)User::objects.filter(...).order_by(...) (via impl_objects!)
RelationsForeignKey, ManyToMany, OneToOneStandard SeaORM relations
Transactionswith transaction.atomic()db.transaction(...)
Multi-DByesPostgreSQL, MySQL, SQLite
NoSQLvia 3rd partyvia 3rd party crates (e.g., mongodb)

Authentication

FeatureDjangoRunique
Login / Logoutauthenticate() + login()auth_login(...), logout()
Is Authenticatedrequest.user.is_authenticatedis_authenticated(&session).await
Current Userrequest.userCurrentUser (injected via middleware)
Route protection@login_requiredif !is_authenticated(&session).await { ... } pattern
Sessionsnativetower-sessions (DB backend)
Brute force protectiondjango-axes (3rd party)Native LoginGuard (auto lockout)
Password HashingPBKDF2 / Argon2Argon2 by default, multi-algo support
Account Activationnative (auth)Integrated into password creation/reset flow
Reset passwordnativehandle_forgot_password + handle_password_reset native
Force logoutyesRuniqueSessionStore::invalidate_all(user_id)

Security

FeatureDjangoRunique
CSRFnativenative (constant-time validation)
CSPdjango-csp (3rd party)native (use_nonce: true by default)
HSTSSECURE_HSTS_SECONDSnative
SameSite cookiesconfigurableStrict by default
HttpOnly cookiesby defaultalways true
Rate limitingdjango-ratelimit (3rd party)Native RateLimiter
Input sanitizationNative sanitize middleware
Secret keymanualauto-generated on runique new

Admin Interface

FeatureDjangoRunique
Activationadmin.site.register(Model)admin!{} macro
Full CRUDnativenative
List paginationnative.pagination(n) in DisplayConfig
list_displaynative.columns_include() / .columns_exclude()
Search / filtersnative.list_filter() + auto search field
Custom templatesyesyes (Tera hierarchy)
Permissionsper resourceDynamic RBAC (Groups / Permissions)

Email

FeatureDjangoRunique
Send mailsend_mail() nativeutils::Email::new().send() native
Email templatesnativeTera templates supported via html(body)
SMTP Backendconfigurableconfiguration via .env

Internationalization

FeatureDjangoRunique
Languagesunlimited9 default languages (compiled JSON)
Fallbackyesyes (Lang::En)
t("key")_("...")t("section.key")

Performance & Deployment

AspectDjangoRunique
RuntimeCPython (interpreted)Tokio async Rust (compiled)
Memory usage~50–100 MB~5–15 MB
Compilationsingle static binary

What Runique is still missing (compared to Django)

Runique is getting close to Django''s functional completeness, but some pillars are still being worked on:

  • Enhanced File Upload: Server-side automatic image resizing/cropping.
  • Equivalent to django-simple-history: Integrated audit log system to track row changes history.
  • Native NoSQL (Still out of main scope, but simplified MongoDB integration is planned).
  • request.path_param() / request.query_param() — currently via raw Axum extractors (see roadmap).