from django.db import models class SimulationScenario(models.Model): class ScenarioType(models.TextChoices): SINGLE = "single", "Single Simulation" CROP_COMPARISON = "crop_comparison", "Crop Comparison" FERTILIZATION_COMPARISON = ( "fertilization_comparison", "Fertilization Comparison", ) class Status(models.TextChoices): PENDING = "pending", "Pending" RUNNING = "running", "Running" SUCCESS = "success", "Success" FAILURE = "failure", "Failure" name = models.CharField(max_length=255, blank=True, default="") scenario_type = models.CharField( max_length=64, choices=ScenarioType.choices, default=ScenarioType.SINGLE, db_index=True, ) model_name = models.CharField(max_length=128, default="Wofost81_NWLP_CWB_CNB") status = models.CharField( max_length=32, choices=Status.choices, default=Status.PENDING, db_index=True, ) input_payload = models.JSONField(default=dict, blank=True) result_payload = models.JSONField(default=dict, blank=True) error_message = models.TextField(blank=True, default="") created_at = models.DateTimeField(auto_now_add=True, db_index=True) updated_at = models.DateTimeField(auto_now=True) class Meta: ordering = ["-created_at"] verbose_name = "Simulation Scenario" verbose_name_plural = "Simulation Scenarios" def __str__(self): return self.name or f"{self.scenario_type}:{self.pk}" class SimulationRun(models.Model): scenario = models.ForeignKey( SimulationScenario, on_delete=models.CASCADE, related_name="runs", ) run_key = models.CharField(max_length=64) label = models.CharField(max_length=255) status = models.CharField( max_length=32, choices=SimulationScenario.Status.choices, default=SimulationScenario.Status.PENDING, db_index=True, ) weather_payload = models.JSONField(default=list, blank=True) soil_payload = models.JSONField(default=dict, blank=True) crop_payload = models.JSONField(default=dict, blank=True) site_payload = models.JSONField(default=dict, blank=True) agromanagement_payload = models.JSONField(default=list, blank=True) result_payload = models.JSONField(default=dict, blank=True) error_message = models.TextField(blank=True, default="") created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: ordering = ["scenario_id", "id"] constraints = [ models.UniqueConstraint( fields=["scenario", "run_key"], name="crop_simulation_unique_run_key_per_scenario", ) ] verbose_name = "Simulation Run" verbose_name_plural = "Simulation Runs" def __str__(self): return f"{self.scenario_id}:{self.run_key}"