Skip to main content

A modern Python web framework built on FastAPI with Django-like features and structure

Project description

Rango API Framework

A modern Python web framework built on FastAPI with Django-like features for rapid API development.

Features

  • FastAPI Integration: Built on top of FastAPI for high performance and automatic API documentation
  • Django-like Structure: Familiar project and app structure similar to Django
  • ORM Integration: Built-in Tortoise ORM support with migrations
  • Generic Views: Pre-built views for common CRUD operations
  • Serializers: Django REST Framework-like serializers
  • CLI Tools: Command-line interface for project management
  • CORS Middleware: Built-in CORS support

Installation

pip install rango-api

Quick Start

1. Create a new project

rango startproject myproject
cd myproject

2. Create an app

rango startapp blog

Initialize database

Init Aerich config

aerich init -t project.settings.TORTOISE_ORM

Create database & initial migration

aerich init-db

Make migrations after changing models

aerich migrate --name "initial"
aerich upgrade

Every time you create or modify models: aerich migrate --name "your_message" → aerich upgrade

3. Run migrations

rango makemigrations
rango migrate

4. Start the development server

rango runserver

Tutorial

Create models with ForeignKey

from tortoise import fields, models

class Category(models.Model):
    id = fields.IntField(pk=True)
    name = fields.CharField(max_length=100)

class Product(models.Model):
    id = fields.IntField(pk=True)
    title = fields.CharField(max_length=255)
    category = fields.ForeignKeyField('models.Category', related_name='products')

Serializers (nested FK supported)

from rango_api.serializers import ModelSerializer
from .models import Category, Product

class CategorySerializer(ModelSerializer):
    class Meta:
        model = Category
        fields = ["id", "name"]

class ProductSerializer(ModelSerializer):
    class Meta:
        model = Product
        fields = ["id", "title", "category"]  # can send category or category_id
        nested_serializers = {
            'Category': CategorySerializer
        }

Views (generic, with FK optimization)

from rango_api.generics import ListCreateView, RetrieveUpdateDeleteView
from .models import Product
from .serializers import ProductSerializer

class ProductListCreateView(ListCreateView):
    model = Product
    serializer_class = ProductSerializer
    select_related = ['category']  # optimize FK

class ProductDetailView(RetrieveUpdateDeleteView):
    model = Product
    serializer_class = ProductSerializer
    select_related = ['category']

URLs

from rango_api.router import Router
from .views import ProductListCreateView, ProductDetailView

router = Router()
router.add("/products", ProductListCreateView, methods=["GET", "POST"])
router.add("/products/{id}", ProductDetailView, methods=["GET", "PUT", "PATCH", "DELETE"])

Test the API

  • Create category:
curl -X POST http://127.0.0.1:8000/categories \
  -H "Content-Type: application/json" \
  -d '{"name":"Electronics"}'
  • Create product (supports category or category_id):
curl -X POST http://127.0.0.1:8000/products \
  -H "Content-Type: application/json" \
  -d '{"title":"Phone","category":1}'

Extensibility (DRF-like Hooks)

You can override hooks in generic views to customize behavior:

class ProductListCreateView(ListCreateView):
    model = Product
    serializer_class = ProductSerializer

    def get_queryset(self, request):
        return self.model.all().select_related('category')

    async def before_create(self, request, data: dict) -> dict:
        # mutate/validate incoming data
        data.setdefault("title", data.get("title", "Untitled"))
        return data

    async def after_create(self, request, obj):
        # side-effects, logging, etc.
        return obj

class ProductDetailView(RetrieveUpdateDeleteView):
    model = Product
    serializer_class = ProductSerializer

    async def before_update(self, request, obj, data: dict) -> dict:
        # e.g. normalize FK input
        if 'category' in data and 'category_id' not in data:
            data['category_id'] = data.pop('category')
        return data

Available hooks include: get_queryset, filter_queryset, before_create, perform_create, after_create, before_update, perform_update, after_update, before_delete, perform_delete, after_delete.

Project Structure

myproject/
├── apps/
│   └── blog/
│       ├── models.py
│       ├── serializers.py
│       ├── views.py
│       └── urls.py
├── project/
│   ├── settings.py
│   ├── urls.py
│   ├── views.py
│   └── asgi.py
├── main.py
└── manage.py

Basic Usage

Models

from tortoise import fields, models

class Post(models.Model):
    title = fields.CharField(max_length=255)
    content = fields.TextField()
    created_at = fields.DatetimeField(auto_now_add=True)

Serializers

from rango_api.serializers import ModelSerializer
from .models import Post

class PostSerializer(ModelSerializer):
    class Meta:
        model = Post
        fields = ["id", "title", "content", "created_at"]

Views

from rango_api.generics import ListCreateView, RetrieveUpdateDeleteView
from .models import Post
from .serializers import PostSerializer

class PostListCreateView(ListCreateView):
    model = Post
    serializer_class = PostSerializer

class PostDetailView(RetrieveUpdateDeleteView):
    model = Post
    serializer_class = PostSerializer

URLs

from rango_api.router import Router
from .views import PostListCreateView, PostDetailView

router = Router()
router.add("/posts", PostListCreateView, methods=["GET", "POST"])
router.add("/posts/{id}", PostDetailView, methods=["GET", "PUT", "DELETE"])

CLI Commands

  • rango startproject <name> - Create a new project
  • rango startapp <name> - Create a new app
  • rango makemigrations [message] - Create database migrations
  • rango migrate - Apply database migrations
  • rango runserver [host] [port] - Start development server

Requirements

  • Python 3.8+
  • FastAPI
  • Tortoise ORM
  • Uvicorn

License

This project is licensed under the MIT License - see the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Support

If you have any questions or need help, please open an issue on GitHub.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rango_api-0.1.0.tar.gz (18.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rango_api-0.1.0-py3-none-any.whl (17.0 kB view details)

Uploaded Python 3

File details

Details for the file rango_api-0.1.0.tar.gz.

File metadata

  • Download URL: rango_api-0.1.0.tar.gz
  • Upload date:
  • Size: 18.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for rango_api-0.1.0.tar.gz
Algorithm Hash digest
SHA256 510d17c9581e4cc1e235bafd6ef32f1e858bd6ce24ce4b8f1a456c2434b6cb58
MD5 58bd68e51c9408503a2dbef475985694
BLAKE2b-256 3145d70a56b6f4eeab19b8c1b6523d36f08517f072516bae684504582e524354

See more details on using hashes here.

File details

Details for the file rango_api-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: rango_api-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 17.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for rango_api-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 436e5b6bb83d613728c5dcc08f6f2f16094f8ab0e0776303f8f1b8d76b4d6b49
MD5 944dec4173625e089e5c95dafd96a5a7
BLAKE2b-256 b7b9bae5c5f9f2726ac62082f1064f457bc607e19b127fdbdb1336a7b263f36d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page