Aggify یک ODM مدرن و async-first برای MongoDB است که API آن شبیه Django ORM است، ولی به Django وابسته نیست؛
همان مدلها در FastAPI، gRPC (grpc.aio)، Django (viewهای sync و async)، اسکریپتها و workerها کار میکنند.
pip install aggify # هسته (فقط pymongo)
pip install "aggify[fastapi]" # Pydantic و FastAPI
pip install "aggify[django]"
pip install "aggify[grpc]"import aggify
from aggify import Document, StringField, IntField, Q, F, Count, Sum
aggify.connect("mongodb://localhost:27017/shop") # فقط تنظیمات را ثبت میکند؛ اتصال lazy است
class Book(Document):
title = StringField(required=True)
year = IntField(min_value=0)
class Meta:
collection = "books"
ordering = ["year"]
# sync
Book.objects.create(title="Dune", year=1965)
Book.objects.filter(Q(year__lt=1900) | Q(title__icontains="du")).order_by("-year")[:10]
# async (هر متد I/O یک نسخهی a-دار دارد)
book = await Book.objects.aget(title="Dune")
book.year = 1966
await book.asave() # فقط {"$set": {"year": 1966}} فرستاده میشودکوئریهای پیچیدهی Mongo (join، group، facet، window) بهجای نوشتن pipeline دستی، با همان سبک Django ساخته میشوند:
(Order.objects.filter(status="paid", customer__country="DE") # $lookup + $unwind + $match خودکار
.values("customer__name")
.annotate(revenue=Sum("total"), orders=Count()) # $group
.filter(orders__gte=3) # HAVING
.order_by("-revenue")[:10])هر زمان qs.query را بزنید، دقیقاً همان چیزی که به MongoDB فرستاده میشود را میبینید. برای مرحلههایی که queryset ندارد
($facet, $bucket, $setWindowFields, $graphLookup ...) از Aggify(Model) استفاده کنید.
نمونههای واقعی و اجراشده در Cookbook هستند.
- FastAPI:
aggify.contrib.fastapi(lifespan,get_or_404,Pagination, مپ خطاها به HTTP) وpydantic_model(Model)برای ساخت خودکار schema ورودی/خروجی. - gRPC:
@grpc_errorsخطاهای Aggify را به status code درست gRPC تبدیل میکند؛fill_message/message_to_kwargsبین protobuf و مدل تبدیل میکنند. - Django:
INSTALLED_APPS += ["aggify.contrib.django"]و تنظیمAGGIFY = {...}؛get_object_or_404، Paginator، فرم، میدلور تراکنش، وObjectIdFieldبرای نگهداشتن id مونگو داخل مدلهای SQL جنگو.
- NoSQL injection: مقدارها قبل از رسیدن به کوئری توسط نوع فیلد بررسی میشوند؛
filter(username={"$ne": ""})خطا میدهد. - Regex:
containsو بقیه ورودی را escape میکنند؛ فقطregexصریح الگو میپذیرد (با سقف طول). - JavaScript سمت سرور (
$where,$function,$accumulator) بهصورت پیشفرض مسدود است. - نام فیلدها اعتبارسنجی میشوند، Mass-assignment با
TypeErrorرد میشود، رمز URI در لاگ ماسک میشود. - سقفهای قابل تنظیم:
max_limit،default_max_time_ms،max_in_list.
جزئیات کامل: Security.
assert_num_queries(n) و capture_commands() برای شمارش کوئریها (مثل assertNumQueries جنگو)،
qs.query / pipeline.to_list() برای تست بدون دیتابیس، و تستهای differential با Hypothesis که ۲۵۰ کوئری تصادفی را
با MongoDB واقعی و یک مرجع پایتونی مقایسه میکنند. جزئیات: Testing.
- از MongoEngine: راهنمای مهاجرت — دادهها سازگارند و میتوان مدلبهمدل مهاجرت کرد.
- از Aggify نسخهی 0.x: تغییرات.