fixes but still nto fixed

This commit is contained in:
IGNY8 VPS (Salman)
2026-01-15 04:13:54 +00:00
parent e02ba76451
commit 75785aa642
12 changed files with 1037 additions and 80 deletions

View File

@@ -757,20 +757,109 @@ class KeywordViewSet(SiteSectorModelViewSet):
def filter_options(self, request):
"""
Get distinct filter values from current data.
Returns only countries and statuses that exist in the current site's keywords.
Returns only values that exist in the filtered queryset.
Supports cascading filters - pass current filter values to get remaining options.
"""
import logging
from django.db.models import Q
from django.db.models.functions import Coalesce
logger = logging.getLogger(__name__)
try:
queryset = self.get_queryset()
# Get distinct countries from seed_keyword (use set for proper deduplication)
countries = list(set(queryset.values_list('seed_keyword__country', flat=True)))
countries = sorted([c for c in countries if c]) # Sort and filter nulls
# Apply current filters to get cascading options
# Each filter's options are based on data that matches OTHER filters
status_filter = request.query_params.get('status')
country_filter = request.query_params.get('country')
cluster_filter = request.query_params.get('cluster_id')
difficulty_min = request.query_params.get('difficulty_min')
difficulty_max = request.query_params.get('difficulty_max')
# Base queryset for each filter option calculation
# For countries: apply status, cluster, difficulty filters
countries_qs = queryset
if status_filter:
countries_qs = countries_qs.filter(status=status_filter)
if cluster_filter:
countries_qs = countries_qs.filter(cluster_id=cluster_filter)
if difficulty_min is not None:
try:
countries_qs = countries_qs.filter(
Q(difficulty_override__gte=int(difficulty_min)) |
Q(difficulty_override__isnull=True, seed_keyword__difficulty__gte=int(difficulty_min))
)
except (ValueError, TypeError):
pass
if difficulty_max is not None:
try:
countries_qs = countries_qs.filter(
Q(difficulty_override__lte=int(difficulty_max)) |
Q(difficulty_override__isnull=True, seed_keyword__difficulty__lte=int(difficulty_max))
)
except (ValueError, TypeError):
pass
# For statuses: apply country, cluster, difficulty filters
statuses_qs = queryset
if country_filter:
statuses_qs = statuses_qs.filter(seed_keyword__country=country_filter)
if cluster_filter:
statuses_qs = statuses_qs.filter(cluster_id=cluster_filter)
if difficulty_min is not None:
try:
statuses_qs = statuses_qs.filter(
Q(difficulty_override__gte=int(difficulty_min)) |
Q(difficulty_override__isnull=True, seed_keyword__difficulty__gte=int(difficulty_min))
)
except (ValueError, TypeError):
pass
if difficulty_max is not None:
try:
statuses_qs = statuses_qs.filter(
Q(difficulty_override__lte=int(difficulty_max)) |
Q(difficulty_override__isnull=True, seed_keyword__difficulty__lte=int(difficulty_max))
)
except (ValueError, TypeError):
pass
# For clusters: apply status, country, difficulty filters
clusters_qs = queryset
if status_filter:
clusters_qs = clusters_qs.filter(status=status_filter)
if country_filter:
clusters_qs = clusters_qs.filter(seed_keyword__country=country_filter)
if difficulty_min is not None:
try:
clusters_qs = clusters_qs.filter(
Q(difficulty_override__gte=int(difficulty_min)) |
Q(difficulty_override__isnull=True, seed_keyword__difficulty__gte=int(difficulty_min))
)
except (ValueError, TypeError):
pass
if difficulty_max is not None:
try:
clusters_qs = clusters_qs.filter(
Q(difficulty_override__lte=int(difficulty_max)) |
Q(difficulty_override__isnull=True, seed_keyword__difficulty__lte=int(difficulty_max))
)
except (ValueError, TypeError):
pass
# For difficulties: apply status, country, cluster filters
difficulties_qs = queryset
if status_filter:
difficulties_qs = difficulties_qs.filter(status=status_filter)
if country_filter:
difficulties_qs = difficulties_qs.filter(seed_keyword__country=country_filter)
if cluster_filter:
difficulties_qs = difficulties_qs.filter(cluster_id=cluster_filter)
# Get distinct countries
countries = list(set(countries_qs.values_list('seed_keyword__country', flat=True)))
countries = sorted([c for c in countries if c])
# Map country codes to display names
from igny8_core.auth.models import SeedKeyword
country_choices = dict(SeedKeyword.COUNTRY_CHOICES)
country_options = [
@@ -778,9 +867,9 @@ class KeywordViewSet(SiteSectorModelViewSet):
for c in countries
]
# Get distinct statuses (use set for proper deduplication)
statuses = list(set(queryset.values_list('status', flat=True)))
statuses = sorted([s for s in statuses if s]) # Sort and filter nulls
# Get distinct statuses from filtered queryset
statuses = list(set(statuses_qs.values_list('status', flat=True)))
statuses = sorted([s for s in statuses if s])
status_labels = {
'new': 'New',
'mapped': 'Mapped',
@@ -790,9 +879,9 @@ class KeywordViewSet(SiteSectorModelViewSet):
for s in statuses
]
# Get distinct clusters (use set for proper deduplication)
# Get distinct clusters from filtered queryset
cluster_ids = list(set(
queryset.exclude(cluster_id__isnull=True)
clusters_qs.exclude(cluster_id__isnull=True)
.values_list('cluster_id', flat=True)
))
@@ -802,11 +891,48 @@ class KeywordViewSet(SiteSectorModelViewSet):
for c in clusters
]
# Get distinct difficulty levels from filtered queryset (mapped to 1-5 scale)
# Difficulty is stored as 0-100 in seed_keyword, mapped to 1-5 scale
from django.db.models import Case, When, Value, IntegerField
# Get effective difficulty (override or seed_keyword)
difficulty_values = difficulties_qs.annotate(
effective_difficulty=Coalesce('difficulty_override', 'seed_keyword__difficulty')
).exclude(effective_difficulty__isnull=True).values_list('effective_difficulty', flat=True)
# Map raw difficulty (0-100) to 1-5 scale and find unique values
difficulty_levels = set()
for d in difficulty_values:
if d is not None:
if d <= 10:
difficulty_levels.add(1)
elif d <= 30:
difficulty_levels.add(2)
elif d <= 50:
difficulty_levels.add(3)
elif d <= 70:
difficulty_levels.add(4)
else:
difficulty_levels.add(5)
difficulty_labels = {
1: '1 - Very Easy',
2: '2 - Easy',
3: '3 - Medium',
4: '4 - Hard',
5: '5 - Very Hard',
}
difficulty_options = [
{'value': str(d), 'label': difficulty_labels[d]}
for d in sorted(difficulty_levels)
]
return success_response(
data={
'countries': country_options,
'statuses': status_options,
'clusters': cluster_options,
'difficulties': difficulty_options,
},
request=request
)
@@ -1130,6 +1256,45 @@ class ClusterViewSet(SiteSectorModelViewSet):
return success_response(data={'deleted_count': deleted_count}, request=request)
@action(detail=False, methods=['get'], url_path='filter_options', url_name='filter_options')
def filter_options(self, request):
"""
Get distinct filter values from current data.
Returns only statuses that exist in the current site's clusters.
"""
import logging
logger = logging.getLogger(__name__)
try:
queryset = self.get_queryset()
# Get distinct statuses
statuses = list(set(queryset.values_list('status', flat=True)))
statuses = sorted([s for s in statuses if s])
status_labels = {
'new': 'New',
'mapped': 'Mapped',
}
status_options = [
{'value': s, 'label': status_labels.get(s, s.title())}
for s in statuses
]
return success_response(
data={
'statuses': status_options,
},
request=request
)
except Exception as e:
logger.error(f"Error in filter_options: {str(e)}", exc_info=True)
return error_response(
error=f'Failed to fetch filter options: {str(e)}',
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
request=request
)
@action(detail=False, methods=['post'], url_path='auto_generate_ideas', url_name='auto_generate_ideas')
def auto_generate_ideas(self, request):
"""Auto-generate ideas for clusters using IdeasService"""
@@ -1308,6 +1473,90 @@ class ContentIdeasViewSet(SiteSectorModelViewSet):
serializer.save(account=account, site=site, sector=sector)
@action(detail=False, methods=['get'], url_path='filter_options', url_name='filter_options')
def filter_options(self, request):
"""
Get distinct filter values from current data.
Returns only values that exist in the current site's content ideas.
"""
import logging
logger = logging.getLogger(__name__)
try:
queryset = self.get_queryset()
# Get distinct statuses
statuses = list(set(queryset.values_list('status', flat=True)))
statuses = sorted([s for s in statuses if s])
status_labels = {
'new': 'New',
'queued': 'Queued',
'completed': 'Completed',
}
status_options = [
{'value': s, 'label': status_labels.get(s, s.title())}
for s in statuses
]
# Get distinct content_types
content_types = list(set(queryset.values_list('content_type', flat=True)))
content_types = sorted([t for t in content_types if t])
type_labels = {
'post': 'Post',
'page': 'Page',
'product': 'Product',
'taxonomy': 'Taxonomy',
}
content_type_options = [
{'value': t, 'label': type_labels.get(t, t.title())}
for t in content_types
]
# Get distinct content_structures
structures = list(set(queryset.values_list('content_structure', flat=True)))
structures = sorted([s for s in structures if s])
structure_labels = {
'article': 'Article', 'guide': 'Guide', 'comparison': 'Comparison',
'review': 'Review', 'listicle': 'Listicle', 'landing_page': 'Landing Page',
'business_page': 'Business Page', 'service_page': 'Service Page',
'general': 'General', 'cluster_hub': 'Cluster Hub',
'product_page': 'Product Page', 'category_archive': 'Category Archive',
'tag_archive': 'Tag Archive', 'attribute_archive': 'Attribute Archive',
}
content_structure_options = [
{'value': s, 'label': structure_labels.get(s, s.replace('_', ' ').title())}
for s in structures
]
# Get distinct clusters with ideas
cluster_ids = list(set(
queryset.exclude(keyword_cluster_id__isnull=True)
.values_list('keyword_cluster_id', flat=True)
))
clusters = Clusters.objects.filter(id__in=cluster_ids).values('id', 'name').order_by('name')
cluster_options = [
{'value': str(c['id']), 'label': c['name']}
for c in clusters
]
return success_response(
data={
'statuses': status_options,
'content_types': content_type_options,
'content_structures': content_structure_options,
'clusters': cluster_options,
},
request=request
)
except Exception as e:
logger.error(f"Error in filter_options: {str(e)}", exc_info=True)
return error_response(
error=f'Failed to fetch filter options: {str(e)}',
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
request=request
)
@action(detail=False, methods=['POST'], url_path='bulk_delete', url_name='bulk_delete')
def bulk_delete(self, request):
"""Bulk delete content ideas"""