from django.db import models class SoilLocation(models.Model): """ مرکز زمین برای داده‌های خاک و مزرعه. هر مختصات سه سطر در SoilDepthData دارد (۰–۵، ۵–۱۵، ۱۵–۳۰ سانتی‌متر). """ latitude = models.DecimalField( max_digits=9, decimal_places=6, db_index=True, help_text="عرض جغرافیایی مرکز زمین (lat)", ) longitude = models.DecimalField( max_digits=9, decimal_places=6, db_index=True, help_text="طول جغرافیایی مرکز زمین (lon)", ) task_id = models.CharField( max_length=255, blank=True, help_text="شناسه تسک Celery در حال پردازش", ) farm_boundary = models.JSONField( default=dict, blank=True, help_text=( "مرز مزرعه برای درخواست‌های سنجش‌ازدور. " 'می‌تواند GeoJSON polygon یا bbox مثل {"type": "Polygon", "coordinates": [...]} باشد.' ), ) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: constraints = [ models.UniqueConstraint( fields=["latitude", "longitude"], name="soil_location_unique_lat_lon", ) ] ordering = ["-updated_at"] verbose_name = "مرکز زمین" verbose_name_plural = "مراکز زمین" def __str__(self): return f"SoilLocation({self.latitude}, {self.longitude})" @property def center_latitude(self): return self.latitude @property def center_longitude(self): return self.longitude @property def is_complete(self): """آیا هر سه عمق ذخیره شده‌اند؟""" return self.depths.count() == 3 class SoilDepthData(models.Model): """ داده‌های خاک برای یک عمق مشخص، مرتبط با یک SoilLocation. مقادیر خام از API SoilGrids (قبل از اعمال d_factor). """ DEPTH_0_5 = "0-5cm" DEPTH_5_15 = "5-15cm" DEPTH_15_30 = "15-30cm" DEPTH_CHOICES = [ (DEPTH_0_5, "۰–۵ سانتی‌متر"), (DEPTH_5_15, "۵–۱۵ سانتی‌متر"), (DEPTH_15_30, "۱۵–۳۰ سانتی‌متر"), ] soil_location = models.ForeignKey( SoilLocation, on_delete=models.CASCADE, related_name="depths", ) depth_label = models.CharField( max_length=10, choices=DEPTH_CHOICES, db_index=True, ) # خواص خاک — مقادیر mean از API (raw) bdod = models.FloatField(null=True, blank=True) cec = models.FloatField(null=True, blank=True) cfvo = models.FloatField(null=True, blank=True) clay = models.FloatField(null=True, blank=True) nitrogen = models.FloatField(null=True, blank=True) ocd = models.FloatField(null=True, blank=True) ocs = models.FloatField(null=True, blank=True) phh2o = models.FloatField(null=True, blank=True) sand = models.FloatField(null=True, blank=True) silt = models.FloatField(null=True, blank=True) soc = models.FloatField(null=True, blank=True) wv0010 = models.FloatField(null=True, blank=True) wv0033 = models.FloatField(null=True, blank=True) wv1500 = models.FloatField(null=True, blank=True) created_at = models.DateTimeField(auto_now_add=True) class Meta: constraints = [ models.UniqueConstraint( fields=["soil_location", "depth_label"], name="soil_depth_unique_location_depth", ) ] ordering = ["soil_location", "depth_label"] def __str__(self): return f"SoilDepthData({self.soil_location_id}, {self.depth_label})"