seed keywords
This commit is contained in:
@@ -838,14 +838,133 @@ class SeedKeywordViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Filter by industry and sector if provided."""
|
||||
queryset = super().get_queryset()
|
||||
industry_id = self.request.query_params.get('industry_id')
|
||||
industry_name = self.request.query_params.get('industry_name')
|
||||
sector_id = self.request.query_params.get('sector_id')
|
||||
sector_name = self.request.query_params.get('sector_name')
|
||||
|
||||
if industry_id:
|
||||
queryset = queryset.filter(industry_id=industry_id)
|
||||
if industry_name:
|
||||
queryset = queryset.filter(industry__name__icontains=industry_name)
|
||||
if sector_id:
|
||||
queryset = queryset.filter(sector_id=sector_id)
|
||||
if sector_name:
|
||||
queryset = queryset.filter(sector__name__icontains=sector_name)
|
||||
|
||||
return queryset
|
||||
|
||||
@action(detail=False, methods=['post'], url_path='import_seed_keywords', url_name='import_seed_keywords')
|
||||
def import_seed_keywords(self, request):
|
||||
"""
|
||||
Import seed keywords from CSV (Admin/Superuser only).
|
||||
Expected columns: keyword, industry_name, sector_name, volume, difficulty, intent
|
||||
"""
|
||||
import csv
|
||||
from django.db import transaction
|
||||
|
||||
# Check admin/superuser permission
|
||||
if not (request.user.is_staff or request.user.is_superuser):
|
||||
return error_response(
|
||||
error='Admin or superuser access required',
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
request=request
|
||||
)
|
||||
|
||||
if 'file' not in request.FILES:
|
||||
return error_response(
|
||||
error='No file provided',
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
request=request
|
||||
)
|
||||
|
||||
file = request.FILES['file']
|
||||
if not file.name.endswith('.csv'):
|
||||
return error_response(
|
||||
error='File must be a CSV',
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
request=request
|
||||
)
|
||||
|
||||
try:
|
||||
# Parse CSV
|
||||
decoded_file = file.read().decode('utf-8')
|
||||
csv_reader = csv.DictReader(decoded_file.splitlines())
|
||||
|
||||
imported_count = 0
|
||||
skipped_count = 0
|
||||
errors = []
|
||||
|
||||
with transaction.atomic():
|
||||
for row_num, row in enumerate(csv_reader, start=2): # Start at 2 (header is row 1)
|
||||
try:
|
||||
keyword_text = row.get('keyword', '').strip()
|
||||
industry_name = row.get('industry_name', '').strip()
|
||||
sector_name = row.get('sector_name', '').strip()
|
||||
|
||||
if not all([keyword_text, industry_name, sector_name]):
|
||||
skipped_count += 1
|
||||
continue
|
||||
|
||||
# Get or create industry
|
||||
industry = Industry.objects.filter(name=industry_name).first()
|
||||
if not industry:
|
||||
errors.append(f"Row {row_num}: Industry '{industry_name}' not found")
|
||||
skipped_count += 1
|
||||
continue
|
||||
|
||||
# Get or create industry sector
|
||||
sector = IndustrySector.objects.filter(
|
||||
industry=industry,
|
||||
name=sector_name
|
||||
).first()
|
||||
if not sector:
|
||||
errors.append(f"Row {row_num}: Sector '{sector_name}' not found for industry '{industry_name}'")
|
||||
skipped_count += 1
|
||||
continue
|
||||
|
||||
# Check if keyword already exists
|
||||
existing = SeedKeyword.objects.filter(
|
||||
keyword=keyword_text,
|
||||
industry=industry,
|
||||
sector=sector
|
||||
).first()
|
||||
|
||||
if existing:
|
||||
skipped_count += 1
|
||||
continue
|
||||
|
||||
# Create seed keyword
|
||||
SeedKeyword.objects.create(
|
||||
keyword=keyword_text,
|
||||
industry=industry,
|
||||
sector=sector,
|
||||
volume=int(row.get('volume', 0) or 0),
|
||||
difficulty=int(row.get('difficulty', 0) or 0),
|
||||
intent=row.get('intent', 'informational') or 'informational',
|
||||
is_active=True
|
||||
)
|
||||
imported_count += 1
|
||||
|
||||
except Exception as e:
|
||||
errors.append(f"Row {row_num}: {str(e)}")
|
||||
skipped_count += 1
|
||||
|
||||
return success_response(
|
||||
data={
|
||||
'imported': imported_count,
|
||||
'skipped': skipped_count,
|
||||
'errors': errors[:10] if errors else [] # Limit errors to first 10
|
||||
},
|
||||
message=f'Import completed: {imported_count} keywords imported, {skipped_count} skipped',
|
||||
request=request
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return error_response(
|
||||
error=f'Failed to import keywords: {str(e)}',
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
request=request
|
||||
)
|
||||
|
||||
|
||||
# ============================================================================
|
||||
|
||||
Reference in New Issue
Block a user