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
Migrations (rollback)python manage.py migrate app 0001runique migration down --files ...
Migration statusrunique migration status
Create superuserpython manage.py createsuperuserrunique create-superuser
Startpython manage.py runservercargo runrunique start to (re)generate the admin panel

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
Typed path paramkwargs['id'] (always str in Django)request.get_path_as::<i32>("id")
Raw path paramkwargs['id']request.get_path("id")
Single query paramrequest.GET.get('key')request.get_query("key")
Full query stringrequest.GETrequest.query::<MyStruct>() (deserializes to Deserialize struct)
HTTP headersrequest.META['HTTP_X_FOO']request.headers.get("x-foo")

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(...) or SeaORM query builders
Template renderrender(request, "template.html", ctx)request.render("template.html")
Redirectredirect("url_name")Redirect::to("/url") or reverse(&engine, "name")
Flash messagesmessages.success(request, "...")success!, error!, info!, warning! macros
Secondary connectionsDATABASES['mongo']engine.extension::<mongodb::Client>() (multi-type TypeMap)

Forms

FeatureDjangoRunique
Definitionclass MyForm(ModelForm)#[form] struct or manual RuniqueForm
Validationform.is_valid()form.is_valid().await
Available fieldsCharField, EmailField, FileField, etc.TextField, EmailField, PasswordField, HiddenField, ChoiceField, NumericField, BooleanField, FileField, DateField, TimeField, DateTimeField, DurationField, PhoneField
HTML rendering{{ form.as_p }}{% form.my_form %} (full) or {% form.my_form.field %}
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_string("key"), form.cleaned_i32(...), etc.
Async validationnoyes (DB access in clean())
Cross-field validationclean()clean() async
File fieldsFileFieldFileField native multipart with type/size validation
HTML sanitizationmanualsanitize_rich / sanitize_strict applied to richtext fields

Templates

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

ORM / Database

FeatureDjangoRunique
ORMNative Django ORMSeaORM (Rust async)
Model definitionclass User(models.Model)model!{} macro (v1 SQL types or v2 semantic types)
Auto migrationsyes (change detection)runique makemigrations
Chainable QuerySetUser.objects.filter(...).order_by(...)User::objects.filter(...).order_by(...)
Strict .get()raises MultipleObjectsReturned.one() — returns Err if multiple rows
Random orderingorder_by('?').order_by_random()
Expression ordering.order_by_expr(expr, order)
RelationsForeignKey, ManyToMany, OneToOneStandard SeaORM relations
Transactionswith transaction.atomic()db.transaction(...)
Multi-engine SQLyesPostgreSQL, MySQL, SQLite
Secondary connectionsDATABASES multiple entries.with_custom_db::<T>() × N types (TypeMap)
Framework table extensionextend!{}ALTER TABLE ADD COLUMN on eihwaz_* tables

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(...).await { redirect }
Sessionsnativetower-sessions (MemoryStore + DB fallback)
Brute force protectiondjango-axes (3rd party)Native LoginGuard (auto lockout)
Password hashingPBKDF2 / Argon2Argon2 by default
Password resetnativenative — email template customizable via .email_template("...")
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
Open Redirectnative — all 3xx responses validated (slot 25)
CORSdjango-cors-headers (3rd party)native via .with_cors(...)
Permissions-Policynative — secure preset by default
Trusted Proxies / XFFSECURE_PROXY_SSL_HEADER (partial)native — full XFF chain validation, RFC 1918 preset
Secret keymanualauto-generated on runique new

Admin Panel

FeatureDjangoRunique
Registrationadmin.site.register(Model)admin!{} macro
Full CRUDnativenative
List paginationnative.page_size(n) (list + history)
list_displaynativelist_display: [["col", "Label"], ...]
FK resolution in list3rd element: ["fk_id", "Label", "table.column"]
Search / filtersnativelist_filter + automatic full-text SQL search — direct columns only, filters not combinable (UI)
Group actionsactionsgroup_action — bool (2 elements) or enum (3 elements, exact value)
Bulk createbulk_create: field — comma-split, inserts N records
Bulk editnative bulk edit on multi-row selection
M2M relationsfilter_horizontal / ManyRelatedFieldm2m: [...] — junction table, automatic diff
Custom admin routesget_urls().extra_routes(vec![...])
Custom templatesyesyes (Tera hierarchy)
Permissionsper resourceDynamic RBAC (Groups / Scoped permissions)
Change historydjango-simple-history (3rd party)native history (created/modified/deleted) with field diff
Builtin configconfigure {} block in admin!{}
Optimistic lockingnative — detects concurrent edits (__original_updated_at)
Admin login brute-force protectiondjango-axes (3rd party)native — LoginGuard + rate limiter on admin login
Account creation email3rd partynative — inject_password: true generates temporary password + email
Partial list refreshnative — list_partial HTMX without full page reload
Fieldsetsfieldsets
Read-only fieldsreadonly_fields
Date hierarchydate_hierarchy
Exportnative CSV
Advanced save buttons"Save and continue" / "Save and add another"

Email

FeatureDjangoRunique
Send mailsend_mail() nativeEmail::new().send() native
Email templatesnativeTera templates via .template("emails/my.html")
SMTP backendconfigurableconfiguration via .env
Dev backend (console)EMAIL_BACKEND = 'console'EMAIL_BACKEND=console in .env

Internationalization

FeatureDjangoRunique
Languagesunlimited9 default languages (compiled JSON)
Fallbackyesyes (Lang::En)
Translation_("...")t("section.key") / tf("...", ["var"])

Performance & Deployment

AspectDjangoRunique
RuntimeCPython (interpreted)Tokio async Rust (compiled)
Memory usage~50–100 MB~5–15 MB
Compilationsingle static binary
ACME / auto-TLScertbot (external)native via acme feature

What Runique is still missing (compared to Django)

  • Image resizing: no server-side auto resize/cropping.
  • Generic public CRUD views: no equivalent to Django's DetailView, ListView, CreateView for public views — planned via crud!{} (in development). The admin panel covers backoffice CRUD via admin!{}.
  • Model signals / hooks: before_save, after_save, before_delete, after_delete — infrastructure in place, generator integration in progress.
  • Management commands: no equivalent to manage.py custom_command — one-shot operations go through src/bin/.
  • Built-in test client: no native HTTP test client — use reqwest or axum::test.
  • Fixtures: no loaddata/dumpdata — seeds are plain Rust functions.
  • Admin inline: no editing of related objects directly inside the parent form.
  • Admin combinable filters: clicking a filter value resets other active column filters — the backend supports multiple simultaneous filters (Vec), but the generated template links do not preserve filters from other columns.
  • Admin FK filters: list_filter supports direct columns only — no relation traversal (article__author__name).
  • Admin fieldsets: no field grouping by section in admin forms (fieldsets in Django).
  • Admin readonly fields: no readonly_fields — non-editable fields must be excluded from the form.
  • Admin date hierarchy: no date_hierarchy to filter the list by year/month/day.
  • Admin export: no native CSV/JSON export from the list view.
  • Admin advanced save buttons: no "Save and continue editing" / "Save and add another".
  • Full i18n: t()/tf() available, but no pluralization or Tera template translation.
  • Sitemap / RSS: not built-in.
  • Third-party authentication: OAuth / OIDC structured (Google, Microsoft, Apple, LDAP, SAML) but flow not implemented — stub only. JWT and API key auth absent.
  • Security observability: CSP report-uri/report-to absent — violations are not collected. Auth event log (successful/failed logins, lockouts) not stored in DB.