Skip to content

Project Layout

Learn the recommended directory structure for Aksara applications.


Standard Project Structure

When you run aksara startproject myproject, you get:

myproject/
├── main.py                 # Application entry point
├── settings.py             # Aksara configuration
├── pyproject.toml          # Project metadata & dependencies
├── requirements.txt        # Pip requirements
├── .env                    # Environment variables (gitignored)
├── .gitignore              # Git ignore rules
├── .pre-commit-config.yaml # Pre-commit hooks
├── .editorconfig           # Editor configuration
├── README.md               # Project documentation
├── app/                    # Default application module
│   ├── __init__.py
│   ├── models.py           # Database models
│   ├── views.py            # ViewSets and API endpoints
│   ├── urls.py             # Route registration
│   └── serializers.py      # Request/response serializers
└── migrations/             # Database migrations
    └── (auto-generated)

File Descriptions

main.py

The application entry point. Initializes the Aksara app and registers routes:

from aksara import Aksara
from app.urls import register_routes

import settings  # noqa: F401 — configures Aksara

app = Aksara(
    database_url=settings.DATABASE_URL,
    title="My Project",
    description="An Aksara application",
    enable_admin=True,
    debug=True,
)

# Register ViewSets from app/urls.py
register_routes(app)

settings.py

Centralized configuration using environment variables:

import os
from aksara import configure

DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://localhost/myproject")
DEBUG = os.getenv("AKSARA_DEBUG", "false").lower() == "true"

configure(
    database_url=DATABASE_URL,
    debug=DEBUG,
    pool_min_size=5,
    pool_max_size=20,
    installed_apps=[
        "aksara.contrib.auth",
        "aksara.contrib.admin",
        "app",
    ],
)

app/models.py

Define your database models:

from aksara import Model, fields

class Article(Model):
    title = fields.String(max_length=200)
    slug = fields.String(max_length=200, unique=True)
    content = fields.Text()
    published = fields.Boolean(default=False)
    created_at = fields.DateTime(auto_now_add=True)

app/views.py

Define ViewSets for your API:

from aksara.api import ModelViewSet
from app.models import Article

class ArticleViewSet(ModelViewSet):
    model = Article
    prefix = "/articles"
    tags = ["Articles"]

app/urls.py

Register your ViewSets:

from aksara import include_viewset
from app.views import ArticleViewSet

urlpatterns = [
    ArticleViewSet,
]

def register_routes(app):
    """Register all routes with the Aksara app."""
    for viewset in urlpatterns:
        include_viewset(app, viewset)

app/serializers.py

Custom serializers for complex validation:

from aksara.api import ModelSerializer
from app.models import Article

class ArticleSerializer(ModelSerializer):
    class Meta:
        model = Article
        fields = ["id", "title", "slug", "content", "published"]
        read_only_fields = ["id"]

    def validate_slug(self, value):
        return value.lower().replace(" ", "-")

Multi-App Structure

For larger projects, organize code into multiple apps:

myproject/
├── main.py
├── settings.py
├── apps/
│   ├── __init__.py
│   ├── blog/
│   │   ├── __init__.py
│   │   ├── models.py
│   │   ├── views.py
│   │   ├── urls.py
│   │   └── serializers.py
│   ├── users/
│   │   ├── __init__.py
│   │   ├── models.py
│   │   ├── views.py
│   │   ├── urls.py
│   │   └── serializers.py
│   └── products/
│       ├── __init__.py
│       ├── models.py
│       ├── views.py
│       ├── urls.py
│       └── serializers.py
└── migrations/
    ├── blog/
    ├── users/
    └── products/

Configure apps in settings.py:

configure(
    installed_apps=[
        "aksara.contrib.auth",
        "aksara.contrib.admin",
        "apps.blog",
        "apps.users",
        "apps.products",
    ],
)

Create new apps using the CLI:

aksara startapp blog --directory apps
aksara startapp users --directory apps

Adding New Apps

Use the startapp command to create a new app:

aksara startapp myapp

This creates:

myapp/
├── __init__.py
├── models.py
├── views.py
├── urls.py
└── serializers.py

Then register it in your settings:

installed_apps=[
    # ... existing apps
    "myapp",
]

And include routes in main.py:

from myapp.urls import register_routes as register_myapp
register_myapp(app)

Migrations Directory

Migrations are stored in the migrations/ directory:

migrations/
├── 0001_initial.py
├── 0002_add_article_slug.py
├── 0003_add_user_profile.py
└── __init__.py

Each migration file contains:

# migrations/0001_initial.py
from aksara.migrations import Migration, operations

class Migration(Migration):
    dependencies = []

    operations = [
        operations.CreateTable(
            "articles",
            columns=[
                operations.UUID(primary_key=True),
                operations.String("title", max_length=200),
                operations.Text("content"),
            ],
        ),
    ]

Static Files and Templates

For admin customization or static assets:

myproject/
├── static/
│   ├── css/
│   ├── js/
│   └── images/
└── templates/
    └── admin/
        └── custom_base.html

Mount static files in main.py:

from fastapi.staticfiles import StaticFiles

app.mount("/static", StaticFiles(directory="static"), name="static")

Tests Directory

Organize tests alongside or separate from your app code:

myproject/
├── tests/
│   ├── __init__.py
│   ├── conftest.py        # Pytest fixtures
│   ├── test_models.py
│   ├── test_views.py
│   └── test_api.py

Example conftest.py:

import pytest
from aksara.testing import TestClient, setup_test_database

@pytest.fixture
async def client():
    await setup_test_database()
    yield TestClient(app)

Best Practices

Keep Apps Focused

Each app should have a single responsibility:

  • blog — Blog posts and categories
  • users — User management
  • misc — Random utilities (avoid this)

Use Consistent Naming

Component Convention Example
Apps lowercase, singular blog, user, product
Models PascalCase, singular Article, User, Product
ViewSets PascalCase + ViewSet ArticleViewSet, UserViewSet
Tables lowercase, plural articles, users, products

Environment-Specific Settings

Use different .env files for environments:

.env              # Local development (gitignored)
.env.example      # Template (committed)
.env.test         # Testing
.env.production   # Production (never commit!)