import csv
from django.core.management.base import BaseCommand, CommandError
from products.models import Product, Category
class Command(BaseCommand):
help = 'Import products from a CSV file'
def add_arguments(self, parser):
parser.add_argument('csv_file', type=str, help='Path to CSV file')
parser.add_argument(
'--clear',
action='store_true',
help='Clear existing products before import',
)
def handle(self, *args, **options):
if options['clear']:
Product.objects.all().delete()
self.stdout.write(self.style.WARNING('Cleared existing products'))
try:
with open(options['csv_file'], 'r') as f:
reader = csv.DictReader(f)
created_count = 0
for row in reader:
category, _ = Category.objects.get_or_create(
name=row['category']
)
Product.objects.create(
name=row['name'],
description=row['description'],
price=row['price'],
category=category,
)
created_count += 1
self.stdout.write(
self.style.SUCCESS(
f'Successfully imported {created_count} products'
)
)
except FileNotFoundError:
raise CommandError(f'File {options["csv_file"]} not found')
except KeyError as e:
raise CommandError(f'Missing required column: {e}')
Management commands are perfect for scripts that need Django's ORM and settings. I create them in management/commands/ and extend BaseCommand. The add_arguments method defines CLI options using argparse. I use self.stdout.write with style helpers for colored output. For long-running imports, I show progress and handle errors gracefully with try-except. Commands are testable with call_command() and can be scheduled with cron or Celery beat. This keeps admin scripts organized and discoverable via ./manage.py help.