mirror of
https://github.com/Dispatcharr/Dispatcharr.git
synced 2026-01-23 02:35:14 +00:00
Enhancement: Optimize channel filtering in StreamViewSet using Count annotation for improved performance on large datasets.
This commit is contained in:
parent
1afb15fb63
commit
f810142493
2 changed files with 67 additions and 62 deletions
|
|
@ -8,6 +8,7 @@ from drf_yasg.utils import swagger_auto_schema
|
|||
from drf_yasg import openapi
|
||||
from django.shortcuts import get_object_or_404, get_list_or_404
|
||||
from django.db import transaction
|
||||
from django.db.models import Count
|
||||
from django.db.models import Q
|
||||
import os, json, requests, logging
|
||||
from urllib.parse import unquote
|
||||
|
|
@ -148,7 +149,8 @@ class StreamViewSet(viewsets.ModelViewSet):
|
|||
|
||||
unassigned = self.request.query_params.get("unassigned")
|
||||
if unassigned == "1":
|
||||
qs = qs.filter(channels__isnull=True)
|
||||
# Use annotation with Count for better performance on large datasets
|
||||
qs = qs.annotate(channel_count=Count('channels')).filter(channel_count=0)
|
||||
|
||||
channel_group = self.request.query_params.get("channel_group")
|
||||
if channel_group:
|
||||
|
|
|
|||
|
|
@ -397,70 +397,73 @@ const StreamsTable = ({ onReady }) => {
|
|||
}));
|
||||
};
|
||||
|
||||
const fetchData = useCallback(async ({ showLoader = true } = {}) => {
|
||||
if (showLoader) {
|
||||
setIsLoading(true);
|
||||
}
|
||||
|
||||
const params = new URLSearchParams();
|
||||
params.append('page', pagination.pageIndex + 1);
|
||||
params.append('page_size', pagination.pageSize);
|
||||
|
||||
// Apply sorting
|
||||
if (sorting.length > 0) {
|
||||
const columnId = sorting[0].id;
|
||||
// Map frontend column IDs to backend field names
|
||||
const fieldMapping = {
|
||||
name: 'name',
|
||||
group: 'channel_group__name',
|
||||
m3u: 'm3u_account__name',
|
||||
};
|
||||
const sortField = fieldMapping[columnId] || columnId;
|
||||
const sortDirection = sorting[0].desc ? '-' : '';
|
||||
params.append('ordering', `${sortDirection}${sortField}`);
|
||||
}
|
||||
|
||||
// Apply debounced filters
|
||||
Object.entries(debouncedFilters).forEach(([key, value]) => {
|
||||
if (value) params.append(key, value);
|
||||
});
|
||||
|
||||
try {
|
||||
const [result, ids, filterOptions] = await Promise.all([
|
||||
API.queryStreamsTable(params),
|
||||
API.getAllStreamIds(params),
|
||||
API.getStreamFilterOptions(params),
|
||||
]);
|
||||
|
||||
setAllRowIds(ids);
|
||||
|
||||
// Set filtered options based on current filters
|
||||
setGroupOptions(filterOptions.groups);
|
||||
setM3uOptions(
|
||||
filterOptions.m3u_accounts.map((m3u) => ({
|
||||
label: m3u.name,
|
||||
value: `${m3u.id}`,
|
||||
}))
|
||||
);
|
||||
|
||||
if (initialDataCount === null) {
|
||||
setInitialDataCount(result.count);
|
||||
const fetchData = useCallback(
|
||||
async ({ showLoader = true } = {}) => {
|
||||
if (showLoader) {
|
||||
setIsLoading(true);
|
||||
}
|
||||
|
||||
// Signal that initial data load is complete
|
||||
if (!hasSignaledReady.current && onReady) {
|
||||
hasSignaledReady.current = true;
|
||||
onReady();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
}
|
||||
const params = new URLSearchParams();
|
||||
params.append('page', pagination.pageIndex + 1);
|
||||
params.append('page_size', pagination.pageSize);
|
||||
|
||||
hasFetchedOnce.current = true;
|
||||
if (showLoader) {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [pagination, sorting, debouncedFilters, onReady]);
|
||||
// Apply sorting
|
||||
if (sorting.length > 0) {
|
||||
const columnId = sorting[0].id;
|
||||
// Map frontend column IDs to backend field names
|
||||
const fieldMapping = {
|
||||
name: 'name',
|
||||
group: 'channel_group__name',
|
||||
m3u: 'm3u_account__name',
|
||||
};
|
||||
const sortField = fieldMapping[columnId] || columnId;
|
||||
const sortDirection = sorting[0].desc ? '-' : '';
|
||||
params.append('ordering', `${sortDirection}${sortField}`);
|
||||
}
|
||||
|
||||
// Apply debounced filters
|
||||
Object.entries(debouncedFilters).forEach(([key, value]) => {
|
||||
if (value) params.append(key, value);
|
||||
});
|
||||
|
||||
try {
|
||||
const [result, ids, filterOptions] = await Promise.all([
|
||||
API.queryStreamsTable(params),
|
||||
API.getAllStreamIds(params),
|
||||
API.getStreamFilterOptions(params),
|
||||
]);
|
||||
|
||||
setAllRowIds(ids);
|
||||
|
||||
// Set filtered options based on current filters
|
||||
setGroupOptions(filterOptions.groups);
|
||||
setM3uOptions(
|
||||
filterOptions.m3u_accounts.map((m3u) => ({
|
||||
label: m3u.name,
|
||||
value: `${m3u.id}`,
|
||||
}))
|
||||
);
|
||||
|
||||
if (initialDataCount === null) {
|
||||
setInitialDataCount(result.count);
|
||||
}
|
||||
|
||||
// Signal that initial data load is complete
|
||||
if (!hasSignaledReady.current && onReady) {
|
||||
hasSignaledReady.current = true;
|
||||
onReady();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
}
|
||||
|
||||
hasFetchedOnce.current = true;
|
||||
if (showLoader) {
|
||||
setIsLoading(false);
|
||||
}
|
||||
},
|
||||
[pagination, sorting, debouncedFilters, onReady]
|
||||
);
|
||||
|
||||
// Bulk creation: create channels from selected streams asynchronously
|
||||
const createChannelsFromStreams = async () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue