
Research
Supply Chain Attack on Axios Pulls Malicious Dependency from npm
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.
rango-api
Advanced tools
A modern Python web framework built on Starlette with Django-like features and structure
A modern Python web framework built on Starlette with Django-like features for rapid API development.
pip install rango-api
# Clone or download the framework
# Use python manage.py commands instead of rango commands
# 1. Create a new project
rango startproject myproject
cd myproject
# 2. Create an app
rango startapp blog
# 3. Initialize database
rango initdb
# 4. Start server
rango runserver
# 1. Create a new project
python manage.py startproject myproject
cd myproject
# 2. Create an app
python manage.py startapp blog
# 3. Initialize database
python manage.py initdb
# 4. Start server
python manage.py runserver
Rango Framework uses Tortoise ORM with Aerich for database migrations, providing a Django-like experience.
# After creating a project and app
python manage.py initdb
# 1. Modify models in your app
# ... edit models.py ...
# 2. Create migrations
python manage.py makemigrations "description of changes"
# 3. Apply migrations
python manage.py migrate
# 4. Check status (optional)
python manage.py migrate_status
For detailed database management guide, see DATABASE_GUIDE.md.
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')
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
}
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']
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"])
curl -X POST http://127.0.0.1:8000/categories \
-H "Content-Type: application/json" \
-d '{"name":"Electronics"}'
curl -X POST http://127.0.0.1:8000/products \
-H "Content-Type: application/json" \
-d '{"title":"Phone","category":1}'
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.
myproject/
├── apps/
│ └── blog/
│ ├── models.py
│ ├── serializers.py
│ ├── views.py
│ └── urls.py
├── project/
│ ├── settings.py
│ ├── urls.py
│ ├── views.py
│ └── asgi.py
├── main.py
└── manage.py
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)
from rango_api.serializers import ModelSerializer
from .models import Post
class PostSerializer(ModelSerializer):
class Meta:
model = Post
fields = ["id", "title", "content", "created_at"]
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
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"])
python manage.py startproject <name> - Create a new projectpython manage.py startapp <name> - Create a new apppython manage.py runserver [host] [port] - Start development serverpython manage.py initdb - Initialize database and Aerich config (first time only)python manage.py makemigrations [message] - Create database migrationspython manage.py migrate - Apply database migrationspython manage.py migrate_status - Show migration statusrango startproject <name> - Create a new projectrango startapp <name> - Create a new apprango initdb - Initialize databaserango makemigrations [message] - Create migrationsrango migrate - Apply migrationsrango migrate_status - Show migration statusrango runserver [host] [port] - Start development serverThis project is licensed under the MIT License - see the LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.
If you have any questions or need help, please open an issue on GitHub.
FAQs
A modern Python web framework built on Starlette with Django-like features and structure
We found that rango-api demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.

Security News
TeamPCP is partnering with ransomware group Vect to turn open source supply chain attacks on tools like Trivy and LiteLLM into large-scale ransomware operations.