Buraq is intentionally designed to mirror Django’s patterns. If you know Django, most of what you know transfers directly — the main difference is adding async/await to your views and ORM calls.
django-admin startproject myproject
python manage.py runserver
buraq startproject myproject
Django
Buraq
from django.urls import path, include
from buraq.urls import path, include
from django.shortcuts import render, redirect
from buraq.shortcuts import render, redirect
from django.shortcuts import get_object_or_404
from buraq.shortcuts import get_object_or_404
from django.shortcuts import get_list_or_404
from buraq.shortcuts import get_list_or_404
from django.urls import reverse_lazy
from buraq.urls import reverse_lazy
from django.db import models
from buraq import models
from django.views.generic import ListView
from buraq.views.generic import ListView
from django.views.generic import DetailView
from buraq.views.generic import DetailView
from django.views.generic import CreateView
from buraq.views.generic import CreateView
from django.views.generic import UpdateView
from buraq.views.generic import UpdateView
from django.views.generic import DeleteView
from buraq.views.generic import DeleteView
from django import forms
from buraq.forms import ModelForm
from django.contrib.auth.decorators import login_required
from buraq.contrib.auth.decorators import login_required
from django.views.decorators.http import require_POST
from buraq.views.decorators.http import require_POST
from django.views.decorators.cache import cache_page
from buraq.views.decorators.cache import cache_page
from django.views.decorators.csrf import csrf_exempt
from buraq.views.decorators.csrf import csrf_exempt
from django.views.decorators.vary import vary_on_headers
from buraq.views.decorators.vary import vary_on_headers
from django.contrib import messages
from buraq.contrib.messages import success, error, info
Django
Buraq
python manage.py runserver
buraq runserver
python manage.py makemigrations
buraq makemigrations
python manage.py migrate
buraq migrate
python manage.py startapp name
buraq startapp name
python manage.py startproject name
buraq startproject name
python manage.py createsuperuser
buraq createsuperuser
python manage.py collectstatic
buraq collectstatic
python manage.py findstatic file
buraq findstatic file
python manage.py shell
buraq shell
python manage.py check
buraq check
python manage.py check --deploy
buraq check --deploy
python manage.py dbshell
buraq dbshell
python manage.py dumpdata
buraq dumpdata
python manage.py loaddata fixture
buraq loaddata fixture
python manage.py flush
buraq flush
python manage.py changepassword
buraq changepassword
python manage.py inspectdb
buraq inspectdb
python manage.py diffsettings
buraq diffsettings
python manage.py sendtestemail
buraq sendtestemail
python manage.py makemessages -l ar
buraq makemessages -l ar
python manage.py compilemessages
buraq compilemessages
python manage.py sqlmigrate abc123
buraq sqlmigrate abc123
python manage.py squashmigrations
buraq squashmigrations
python manage.py optimizemigration
buraq optimizemigration
python manage.py sqlflush
buraq sqlflush
python manage.py sqlsequencereset
buraq sqlsequencereset
python manage.py testserver fixtures/
buraq testserver fixtures/
python manage.py test
buraq test
python manage.py showmigrations
buraq showmigrations
python manage.py clearsessions
buraq clearsessions
python manage.py createcachetable
buraq createcachetable
python manage.py remove_stale_contenttypes
buraq remove_stale_contenttypes
python manage.py version
buraq version
python manage.py worker
buraq worker
django-admin
buraq (same CLI, no separate admin tool)
Most settings follow the same naming convention. Key differences:
Django settings.py
Buraq settings.py
DATABASES = {"default": {...}}
DATABASE_URL = "postgresql+asyncpg://...", or DATABASES as a dict of URLs
INSTALLED_APPS
INSTALLED_APPS
MIDDLEWARE
MIDDLEWARE
TEMPLATES = [{...}]
TEMPLATES_DIR, APP_DIRS, TEMPLATE_OPTIONS
STATIC_URL
STATIC_URL
MEDIA_URL
MEDIA_URL
SECRET_KEY
SECRET_KEY
DEBUG
DEBUG
ALLOWED_HOSTS
ALLOWED_HOSTS
A new Django project lists six apps; a new Buraq project lists one. Nothing is
missing — in Django, listing an app is how you switch it on , and in Buraq four
of those five are already on.
Django lists it because
In Buraq
staticfiles — registers the finders and collectstatic
mounted by the application; each app’s static/ is still found through INSTALLED_APPS, and SERVE_STATIC = False turns the serving off
admin — app-directory templates and AppConfig.ready() autodiscovery
path("/admin", admin.site.urls) in your urlconf does both
messages — a context processor and middleware
plain functions over the session; nothing to register
contenttypes — models and migrations
the same, and optional: only generic relations need it
auth — models, migrations, templates
the same, which is why it is listed
So INSTALLED_APPS in Buraq means one thing: this app contributes models,
migrations, templates, static files, management commands or a ready() hook.
Three of Django’s five contribute none of those here, and listing them would
change nothing at all.
Two are worth adding when you use them:
" buraq.contrib.sessions " , # only for SESSION_ENGINE = "...backends.db"
" buraq.contrib.contenttypes " , # only for generic relations
Your own apps go here for the usual reasons — a listed app’s models are found by
makemigrations, its templates/ and static/ are searched, its
management/commands/ become buraq <name>, and its AppConfig.ready() runs.
from django . db import models
class Post ( models . Model ) :
title = models . CharField ( max_length = 200 )
slug = models . SlugField ( unique = True )
content = models . TextField ()
is_published = models . BooleanField ( default = False )
created_at = models . DateTimeField ( auto_now_add = True )
author = models . ForeignKey ( " auth.User " , on_delete = models . CASCADE )
ordering = [ " -created_at " ]
class Post ( models . Model ) :
title = models . CharField ( max_length = 200 )
slug = models . SlugField ( unique = True )
content = models . TextField ()
is_published = models . BooleanField ( default = False )
created_at = models . DateTimeField ( auto_now_add = True )
author = models . ForeignKey ( " auth.User " , on_delete = models . CASCADE )
ordering = [ " -created_at " ]
Django
Buraq
models.GeneratedField(expression=..., output_field=..., db_persist=True)
models.GeneratedField(expression=..., output_field=..., db_persist=True)
models.CompositePrimaryKey("field1", "field2") in Meta.primary_key
models.CompositePrimaryKey("field1", "field2") in Meta.primary_key
Django
Buraq
Post.objects.all()
await Post.objects.all()
Post.objects.filter(published=True)
await Post.objects.filter(published=True)
Post.objects.get(pk=pk)
await Post.objects.get(pk=pk)
Post.objects.create(title="Hello")
await Post.objects.create(title="Hello")
post.save()
await post.save()
post.delete()
await post.delete()
Post.objects.order_by("-created_at")
await Post.objects.order_by("-created_at")
Post.objects.filter(...).count()
await Post.objects.filter(...).count()
Post.objects.select_related("author")
await Post.objects.select_related("author")
The only difference: every ORM call needs await.
Django
Buraq
from django.db.models import AnyValue
from buraq.orm.aggregates import AnyValue
from django . urls import path , include
path ( " posts/ " , views . PostListView . as_view () , name = " post_list " ) ,
path ( " posts/new/ " , views . PostCreateView . as_view () , name = " post_create " ) ,
path ( " posts/<int:pk>/ " , views . PostDetailView . as_view () , name = " post_detail " ) ,
path ( " api/ " , include ( " myapp.api_urls " )) ,
from buraq . urls import path , include
path ( " /posts " , views . PostListView . as_view () , name = " post_list " ) ,
path ( " /posts/new " , views . PostCreateView . as_view () , name = " post_create " ) ,
path ( " /posts/<int:pk> " , views . PostDetailView . as_view () , name = " post_detail " ) ,
path ( " /api " , include ( " myapp.api_urls " )) ,
from django . shortcuts import render , redirect , get_object_or_404
from django . contrib . auth . decorators import login_required
from django . contrib import messages
def post_create ( request ):
form = PostForm ( request . POST or None )
messages . success ( request , " Post created. " )
return redirect ( " /posts " )
return await render ( request , " posts/form.html " , { " form " : form } )
from buraq . shortcuts import render , redirect , get_object_or_404
from buraq . decorators import login_required
from buraq . contrib . messages import success
async def post_create ( request ):
form = PostForm ( await request . form ())
success ( request , " Post created. " )
return redirect ( " /posts " )
return await render ( request , " posts/form.html " , { " form " : form } )
from django . views . generic import ListView , CreateView
class PostListView ( ListView ) :
template_name = " posts/list.html "
class PostCreateView ( CreateView ) :
template_name = " posts/form.html "
from buraq . views . generic import ListView , CreateView
class PostListView ( ListView ) :
template_name = " posts/list.html "
class PostCreateView ( CreateView ) :
template_name = " posts/form.html "
class PostForm ( forms . ModelForm ) :
fields = [ " title " , " slug " , " content " , " is_published " ]
from buraq . forms import ModelForm
class PostForm ( ModelForm ) :
fields = [ " title " , " slug " , " content " , " is_published " ]
Buraq uses Jinja2 instead of Django’s template engine. The syntax is nearly identical.
Django template
Jinja2 (Buraq)
{% extends "base.html" %}
{% extends "base.html" %}
{% block content %}
{% block content %}
{% for item in items %}
{% for item in items %}
{% if condition %}
{% if condition %}
{% url 'post_list' %}
{{ url('post_list') }}
{{ variable }}
{{ variable }}
{% include "partial.html" %}
{% include "partial.html" %}
{{ variable|upper }}
{{ variable|upper }}
Django
Buraq
STATIC_URL = "/static/"
STATIC_URL = "/static/"
STATIC_ROOT = str(BASE_DIR / "staticfiles")
STATIC_ROOT = str(BASE_DIR / "staticfiles")
STATICFILES_DIRS = [str(BASE_DIR / "static")]
STATICFILES_DIRS = [str(BASE_DIR / "static")]
STATICFILES_STORAGE = "django.contrib.staticfiles.storage.ManifestStaticFilesStorage"
STATICFILES_STORAGE = "buraq.contrib.staticfiles.storage.ManifestStaticFilesStorage"
STATICFILES_FINDERS = [...]
STATICFILES_FINDERS = [...]
MEDIA_ROOT = str(BASE_DIR / "media")
MEDIA_DIR = str(BASE_DIR / "media")
MEDIA_URL = "/media/"
MEDIA_URL = "/media/"
Django requires {% load static %} before using {% static %}. Buraq registers the tag automatically — no load needed:
< link rel = " stylesheet " href = " {% static ' css/style.css ' %} " >
< img src = " {% static ' images/logo.png ' %} " >
{# No {% load %} needed #}
< link rel = " stylesheet " href = " {% static ' css/style.css ' %} " >
< img src = " {% static ' images/logo.png ' %} " >
< link rel = " stylesheet " href = " {{ static ( ' css/style.css ' ) }} " >
< img src = " {{ static ( ' images/logo.png ' ) }} " >
Django
Buraq
django.contrib.staticfiles.finders.FileSystemFinder
buraq.contrib.staticfiles.finders.FileSystemFinder
django.contrib.staticfiles.finders.AppDirectoriesFinder
buraq.contrib.staticfiles.finders.AppDirectoriesFinder
Django
Buraq
django.contrib.staticfiles.storage.StaticFilesStorage
buraq.contrib.staticfiles.storage.StaticFilesStorage
django.contrib.staticfiles.storage.ManifestStaticFilesStorage
buraq.contrib.staticfiles.storage.ManifestStaticFilesStorage
from django . contrib import messages
messages . success ( request , " Saved successfully. " )
messages . error ( request , " Something went wrong. " )
messages . info ( request , " Please verify your email. " )
from buraq . contrib . messages import success , error , info
success ( request , " Saved successfully. " )
error ( request , " Something went wrong. " )
info ( request , " Please verify your email. " )
Template usage is identical in both:
{% for message in messages %}
< div class = " alert alert-{{ message.tags }} " > {{ message }} </ div >
from django . contrib . auth import authenticate , login , logout
from django . contrib . auth . decorators import login_required
user = authenticate ( request , username = username , password = password )
return redirect ( " /dashboard " )
from buraq . contrib . auth import authenticate , login , logout
from buraq . decorators import login_required
async def login_view ( request ):
user = await authenticate ( request , username = username , password = password )
await login ( request , user )
return redirect ( " /dashboard " )
Django
Buraq
django.contrib.auth.backends.ModelBackend
buraq.contrib.auth.backends.ModelBackend
django.contrib.auth.backends.AllowAllUsersModelBackend
buraq.contrib.auth.backends.AllowAllUsersModelBackend
django.contrib.auth.backends.AllowAllUsersRemoteUserBackend
buraq.contrib.auth.backends.AllowAllUsersRemoteUserBackend
Django
Buraq
django.middleware.csp.ContentSecurityPolicyMiddleware
buraq.middleware.csp.ContentSecurityPolicyMiddleware
CONTENT_SECURITY_POLICY = {...}
CONTENT_SECURITY_POLICY = {...}
CONTENT_SECURITY_POLICY_REPORT_ONLY = {...}
CONTENT_SECURITY_POLICY_REPORT_ONLY = {...}
CONTENT_SECURITY_POLICY_NONCE_DIRECTIVES
CONTENT_SECURITY_POLICY_NONCE_DIRECTIVES
from django.views.decorators.csp import csp_override
from buraq.views.decorators.csp import csp_override
from django.views.decorators.csp import csp_report_only_override
from buraq.views.decorators.csp import csp_report_only_override
from django.utils.csp import CSP
from buraq.utils.csp import CSP
Both frameworks sign data the same way — HMAC-SHA256 keyed with SECRET_KEY:
Django
Buraq
from django.core import signing
from buraq.utils import signing
signing.dumps(obj)
signing.dumps(obj)
signing.loads(token, max_age=3600)
signing.loads(token, max_age=3600)
signing.Signer()
signing.Signer()
signing.TimestampSigner()
signing.TimestampSigner()
BadSignature
signing.BadSignature
SignatureExpired
signing.SignatureExpired
The API is identical — only the import path differs.
Django
Buraq
from django.tasks import background_task
from buraq.contrib.tasks import background_task
@background_task
@background_task
@background_task(queue="q", priority=5)
@background_task(queue="q", priority=5)
await task.aenqueue(...)
await task.aenqueue(...)
BaseTaskBackend
buraq.contrib.tasks.backends.base.BaseTaskBackend
TaskResult.arefresh()
result.arefresh()
TASKS = {"default": {"BACKEND": "..."}}
TASKS = {"default": {"BACKEND": "..."}}
Both frameworks use an identical API. The only difference is the import path.
Django
Buraq
from django.test import TestCase
from buraq.test import TestCase
self.captureOnCommitCallbacks()
captureOnCommitCallbacks() context manager from buraq.test
MessagesTestMixin + assertMessages()
from buraq.test import MessagesTestMixin
InMemoryStorage
from buraq.contrib.staticfiles.storage import InMemoryStorage
Every ORM call needs await — this is the biggest change
Views must be async def — synchronous views are not supported
Databases are URLs , not ENGINE/NAME dicts — DATABASES takes several,
and using() and read replicas work; there are no database routers
Jinja2 instead of Django’s template engine — syntax is ~95% compatible
JWT auth is built-in alongside session auth
No syncdb — Alembic handles all migrations via buraq makemigrations
buraq CLI replaces python manage.py