مدیریت کلان داده با Django و AgGrid

ما قصد داریم اپلیکیشنی بسازیم که بتواند حجم زیادی از داده ها را با AgGrid فیلتر و مرتب کند.
ارسال تمام داده های خود به مرورگر یک راه سریع برای شروع با AgGrid است، اما اگر یک میلیون ردیف داشته باشید چه؟ آن وقت است که فیلترینگ و مرتب سازی سمت سرور به کمک می آید.
این راهنما شامل:
- استفاده از AgGrid در حالت اسکرول بی نهایت به طوری که سرور مسئول صفحه بندی، فیلتر کردن و مرتب سازی است.
- پیاده سازی فیلتر، مرتب سازی و صفحه بندی برای AgGrid در بالای کلاس Django ListView
- ایجاد یک فرمان مدیریت جنگو برای پر کردن داده های آزمایشی
اما ابتدا، در اینجا نگاهی اجمالی به آنچه که امروز در حال ساخت آن هستیم می پردازیم:
پیش نمایش پروژه
آیا می خواهید نسخه زنده برنامه را ببینید؟ اکنون می توانید یک کپی از این پروژه ایجاد کرده و آن را امتحان کنید.
یک فورک از پروژه AgGridDemo در Circumeo ایجاد کنید.
راه اندازی برنامه جنگو
بسته ها را نصب کنید و برنامه جنگو را ایجاد کنید.
pip install --upgrade django faker
django-admin startproject bigdata .
python3 manage.py startapp core
هسته را به INSTALLED_APPS
فهرست
# settings.py
INSTALLED_APPS = [
"core",
...
]
اضافه کردن قالب ها
- یک دایرکتوری به نام ایجاد کنید
templates
در داخلcore
برنامه - یک فایل به نام ایجاد کنید
index.html
در داخلtemplates
فهرست راهنما.
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/ag-grid/dist/ag-grid.min.noStyle.js"></script>
<link rel="stylesheet" href="https://unpkg.com/ag-grid/dist/styles/ag-grid.css">
<link rel="stylesheet" href="https://unpkg.com/ag-grid/dist/styles/ag-theme-balham.css">
<style>
#container {
max-width: 1250px;
width: 100%;
height: 100%;
margin: 0px auto;
margin-top: 30px;
}
</style>
</head>
<body>
<div id="container">
<div id="data-grid" style="height: 600px; width: 100%" class="ag-theme-balham"></div>
</div>
<script type="text/javascript" charset="utf-8">
const numberFilterParams = {
filterParams: {
filterOptions: ["equals", "notEqual", "lessThan", "greaterThan"],
suppressAndOrCondition: true,
},
};
var columnDefs = [
{ headerName: "Name", field: "name", filter: "agTextColumnFilter" },
{
headerName: "Description",
field: "description",
filter: "agTextColumnFilter",
},
{ headerName: "Category", field: "category", filter: "agTextColumnFilter" },
{
headerName: "Price",
field: "price",
filter: "agNumberColumnFilter",
...numberFilterParams,
},
{
headerName: "Stock Quantity",
field: "stock_quantity",
filter: "agNumberColumnFilter",
...numberFilterParams,
},
{
headerName: "Rating",
field: "rating",
filter: "agNumberColumnFilter",
...numberFilterParams,
},
];
var gridOptions = {
columnDefs: columnDefs,
defaultColDef: {
filterParams: {
suppressAndOrCondition: true,
},
},
enableServerSideSorting: true,
enableServerSideFilter: true,
rowModelType: "infinite",
cacheBlockSize: 100,
maxBlocksInCache: 10,
};
var dataSource = {
getRows: function (params) {
var filtering = encodeURIComponent(JSON.stringify(params.filterModel));
var sorting = encodeURIComponent(JSON.stringify(params.sortModel));
var startRow = params.startRow;
var endRow = params.endRow;
var url = `/products?startRow=${startRow}&endRow=${endRow}&filter=${filtering}&sort=${sorting}`;
fetch(url)
.then((response) => response.json())
.then((data) => {
params.successCallback(data.rows, data.totalRows);
})
.catch((err) => {
params.failCallback();
});
},
};
var gridDiv = document.querySelector("#data-grid");
new agGrid.Grid(gridDiv, gridOptions);
gridOptions.api.setDatasource(dataSource);
gridOptions.api.sizeColumnsToFit();
</script>
</body>
</html>
افزودن نماها
- موجود را حذف کنید
views.py
فایل. - یک دایرکتوری جدید با نام ایجاد کنید
views
در داخلcore
پوشه - یک فایل جدید با نام ایجاد کنید
index.py
در داخلviews
فهرست راهنما. - موارد زیر را کپی و در آن پیست کنید
index.py
در داخلviews
فهرست راهنما.
from django.shortcuts import render
def index_view(request):
return render(request, "core/index.html")
- فایل دیگری با نام ایجاد کنید
products.py
در همان دایرکتوری - موارد زیر را کپی و در قسمت پیست کنید
products.py
فایل.
import json
from django.views.generic.list import ListView
from django.http import JsonResponse
from django.db.models import Q
from core.models import Product
class ProductListView(ListView):
model = Product
def get_queryset(self):
"""
Convert AgGrid filter and sort objects into a Django query.
An example filter:
{"category": {"type": "contains", "filter": "electronics"}}
"""
queryset = super().get_queryset()
filter_params = self.request.GET.get("filter", None)
if filter_params:
filters = json.loads(filter_params)
q_objects = Q()
for key, filter_info in filters.items():
filter_type = filter_info.get("type")
filter_value = filter_info.get("filter")
if filter_type == "contains":
lookup = f"{key}__icontains"
q_objects &= Q(**{lookup: filter_value})
elif filter_type == "equals":
lookup = f"{key}__exact"
q_objects &= Q(**{lookup: filter_value})
elif filter_type == "notEqual":
lookup = f"{key}__exact"
q_objects &= ~Q(**{lookup: filter_value})
elif filter_type == "greaterThan":
lookup = f"{key}__gt"
q_objects &= Q(**{lookup: filter_value})
elif filter_type == "lessThan":
lookup = f"{key}__lt"
q_objects &= Q(**{lookup: filter_value})
queryset = queryset.filter(q_objects)
sort_params = self.request.GET.get("sort", None)
if sort_params:
sort_objects = json.loads(sort_params)
sort_fields = []
for sort_object in sort_objects:
col_id = sort_object["colId"]
sort_order = sort_object["sort"]
if sort_order == "asc":
sort_fields.append(col_id)
elif sort_order == "desc":
sort_fields.append(f"-{col_id}")
if sort_fields:
queryset = queryset.order_by(*sort_fields)
return queryset
def get(self, request, *args, **kwargs):
start_row = int(request.GET.get("startRow", 0))
end_row = int(request.GET.get("endRow", 100))
queryset = self.get_queryset()
total_rows = queryset.count()
queryset = queryset[start_row:end_row]
products = list(
queryset.values(
"name", "description", "category", "price", "stock_quantity", "rating"
)
)
return JsonResponse({"rows": products, "totalRows": total_rows})
به روز رسانی URL ها
- urls.py را در فهرست اصلی ایجاد کنید.
from django.urls import path
from core.views.index import index_view
from core.views.products import ProductListView
urlpatterns = [
path("", index_view, name="index"),
path("products", ProductListView.as_view(), name="products"),
]
- urls.py موجود را در دایرکتوری bigdata پروژه به روز کنید.
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path("admin/", admin.site.urls),
path("", include("core.urls")),
]
اضافه کردن مدل های پایگاه داده
موجود را بازنویسی کنید models.py
با موارد زیر:
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=255)
description = models.TextField(blank=True)
category = models.CharField(max_length=255)
price = models.DecimalField(max_digits=10, decimal_places=2)
stock_quantity = models.IntegerField()
rating = models.FloatField(blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
افزودن یک فرمان مدیریت جنگو برای داده های تست
- ساختار دایرکتوری را ایجاد کنید
management/commands
در داخلcore
پوشه - فایلی به نام باز کنید
populate_products.py
در دایرکتوری جدید و موارد زیر را وارد کنید.
from faker import Faker
import random
from django.core.management.base import BaseCommand
from core.models import Product
class Command(BaseCommand):
def handle(self, *args, **kwargs):
faker = Faker()
categories = [
'Electronics',
'Books',
'Clothing',
'Home & Garden',
'Toys & Games',
'Sports & Outdoors',
'Health & Beauty',
'Automotive',
'Groceries',
'Pet Supplies'
]
for _ in range(1000):
Product.objects.create(
name=faker.text(max_nb_chars=20).capitalize(),
description=faker.text(),
category=random.choice(categories),
price=round(random.uniform(5.0, 500.0), 2),
stock_quantity=random.randint(0, 100),
rating=round(random.uniform(1.0, 5.0), 1)
)
self.stdout.write(self.style.SUCCESS('Successfully populated the database with products.'))
برای اجرای دستور مدیریت جنگو، یک جلسه پوسته باز کنید.
python3 manage.py populate_products
بالا و در حال اجرا با Django و AgGrid
اکنون آماده هستید که میلیون ها ردیف را بدون خراب کردن برگه های مرورگر مدیریت کنید! فهرست های پایگاه داده را در صورت نیاز اضافه کنید، و می توانید این رویکرد را تا حد زیادی مقیاس کنید.