40240-vm/core/management/commands/seed_demo_data.py
Flatlogic Bot ef6dd13037 D
2026-06-09 23:15:53 +00:00

213 lines
9.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from datetime import timedelta
from django.core.management.base import BaseCommand
from django.utils import timezone
from core.models import JobPosting, JobSource
class Command(BaseCommand):
help = "Seed realistic demo sources and job postings for local MVP reviews."
def add_arguments(self, parser):
parser.add_argument(
"--reset",
action="store_true",
help="Delete existing JobSource and JobPosting records before seeding.",
)
def handle(self, *args, **options):
if options["reset"]:
JobPosting.objects.all().delete()
JobSource.objects.all().delete()
self.stdout.write(self.style.WARNING("Existing sources and jobs deleted."))
today = timezone.localdate()
now = timezone.now()
sources_payload = [
{
"name": "France Travail Dijon",
"family": JobSource.Family.PORTAL,
"url": "https://candidat.francetravail.fr/offres/recherche?lieux=21D",
"status": JobSource.Status.ACTIVE,
"owner": "Ops Team",
"notes": "Primary public feed for Dijon area listings.",
"last_checked_at": now - timedelta(minutes=22),
},
{
"name": "Apec Bourgogne-Franche-Comté",
"family": JobSource.Family.PORTAL,
"url": "https://www.apec.fr/candidat/recherche-emploi.html",
"status": JobSource.Status.ACTIVE,
"owner": "Ops Team",
"notes": "Executive and white-collar roles.",
"last_checked_at": now - timedelta(hours=2),
},
{
"name": "Adecco Dijon Tertiaire",
"family": JobSource.Family.AGENCY,
"url": "https://www.adecco.fr/offres-emploi/?k=dijon",
"status": JobSource.Status.PAUSED,
"owner": "Data Partner",
"notes": "Paused while waiting on extraction rule update.",
"last_checked_at": now - timedelta(days=2),
},
{
"name": "Urgo Group Careers",
"family": JobSource.Family.COMPANY,
"url": "https://careers.urgo-group.com/",
"status": JobSource.Status.ACTIVE,
"owner": "Ops Team",
"notes": "Direct company careers feed.",
"last_checked_at": now - timedelta(minutes=55),
},
{
"name": "SEB Selongey Careers",
"family": JobSource.Family.COMPANY,
"url": "https://www.groupe-seb.com/fr/carrieres",
"status": JobSource.Status.ERROR,
"owner": "Connector Squad",
"notes": "Blocked by anti-bot response, requires parser fallback.",
"last_checked_at": now - timedelta(days=5),
},
]
source_map = {}
for payload in sources_payload:
source, _ = JobSource.objects.update_or_create(url=payload["url"], defaults=payload)
source_map[source.name] = source
jobs_payload = [
{
"source": "France Travail Dijon",
"title": "Développeur Python Django (H/F)",
"company": "Noveo Digital",
"location": "Dijon",
"contract_type": JobPosting.ContractType.CDI,
"remote": True,
"salary": "38k€45k€",
"apply_url": "https://example.com/jobs/python-django-dijon",
"published_at": today - timedelta(days=1),
"description": "Concevoir des APIs Django et maintenir un back-office métier orienté data.",
"is_active": True,
"duplicate_score": 4.10,
},
{
"source": "France Travail Dijon",
"title": "Intégrateur Front-end React",
"company": "Pixel Nordic",
"location": "Dijon",
"contract_type": JobPosting.ContractType.CDD,
"remote": False,
"salary": "34k€",
"apply_url": "https://example.com/jobs/react-integrator",
"published_at": today - timedelta(days=2),
"description": "Intégrer des interfaces performantes et accessibles au sein d'une équipe produit.",
"is_active": True,
"duplicate_score": 1.90,
},
{
"source": "Apec Bourgogne-Franche-Comté",
"title": "Product Owner CMS",
"company": "Cobalt Studio",
"location": "Dijon",
"contract_type": JobPosting.ContractType.CDI,
"remote": True,
"salary": "45k€52k€",
"apply_url": "https://example.com/jobs/product-owner-cms",
"published_at": today - timedelta(days=3),
"description": "Piloter la roadmap d'une plateforme CMS B2B et animer les rituels produit.",
"is_active": True,
"duplicate_score": 0.50,
},
{
"source": "Adecco Dijon Tertiaire",
"title": "Technicien support applicatif",
"company": "Helix Services",
"location": "Chenôve",
"contract_type": JobPosting.ContractType.INTERIM,
"remote": False,
"salary": "13,50€/h",
"apply_url": "https://example.com/jobs/support-applicatif",
"published_at": today - timedelta(days=4),
"description": "Support N1/N2 sur une suite SaaS et suivi d'incidents applicatifs.",
"is_active": True,
"duplicate_score": 6.75,
},
{
"source": "Urgo Group Careers",
"title": "Data Analyst RH",
"company": "Urgo Group",
"location": "Chenôve",
"contract_type": JobPosting.ContractType.CDI,
"remote": True,
"salary": "40k€",
"apply_url": "https://example.com/jobs/data-analyst-rh",
"published_at": today - timedelta(days=5),
"description": "Structurer les tableaux de bord RH et fiabiliser les flux de reporting.",
"is_active": True,
"duplicate_score": 0.30,
},
{
"source": "SEB Selongey Careers",
"title": "Ingénieur QA Automatisation",
"company": "Groupe SEB",
"location": "Selongey",
"contract_type": JobPosting.ContractType.CDI,
"remote": False,
"salary": "42k€48k€",
"apply_url": "https://example.com/jobs/qa-automation",
"published_at": today - timedelta(days=6),
"description": "Automatiser les scénarios de validation et renforcer la non-régression continue.",
"is_active": False,
"duplicate_score": 3.20,
},
{
"source": "Apec Bourgogne-Franche-Comté",
"title": "Chef de projet digital",
"company": "Mutualité Bourgogne",
"location": "Dijon",
"contract_type": JobPosting.ContractType.CDD,
"remote": False,
"salary": "39k€",
"apply_url": "https://example.com/jobs/chef-projet-digital",
"published_at": today - timedelta(days=7),
"description": "Coordonner la refonte d'outils internes et piloter les prestataires externes.",
"is_active": True,
"duplicate_score": 2.40,
},
{
"source": "France Travail Dijon",
"title": "Développeur Full Stack Junior",
"company": "BFC Cloud",
"location": "Dijon",
"contract_type": JobPosting.ContractType.APPRENTICESHIP,
"remote": True,
"salary": "Selon grille alternance",
"apply_url": "https://example.com/jobs/fullstack-junior",
"published_at": today - timedelta(days=8),
"description": "Participer au développement d'un CMS métier avec Django et Vue.",
"is_active": True,
"duplicate_score": 5.60,
},
]
seeded_jobs = 0
for payload in jobs_payload:
source = source_map[payload.pop("source")]
_, created = JobPosting.objects.update_or_create(
source=source,
title=payload["title"],
company=payload["company"],
defaults=payload,
)
if created:
seeded_jobs += 1
self.stdout.write(
self.style.SUCCESS(
f"Demo seed complete: {len(source_map)} sources available, {JobPosting.objects.count()} total job postings ({seeded_jobs} new)."
)
)