Files
Ai/location_data/models.py
T
2026-04-25 17:22:41 +03:30

151 lines
5.0 KiB
Python

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})"
class NdviObservation(models.Model):
location = models.ForeignKey(
SoilLocation,
on_delete=models.CASCADE,
related_name="ndvi_observations",
)
observation_date = models.DateField(db_index=True)
mean_ndvi = models.FloatField()
ndvi_map = models.JSONField(default=dict, blank=True)
vegetation_health_class = models.CharField(max_length=64)
satellite_source = models.CharField(max_length=64, default="sentinel-2")
cloud_cover = models.FloatField(null=True, blank=True)
metadata = models.JSONField(default=dict, blank=True)
created_at = models.DateTimeField(auto_now_add=True, db_index=True)
class Meta:
db_table = "dashboard_data_ndviobservation"
ordering = ["-observation_date", "-created_at"]
constraints = [
models.UniqueConstraint(
fields=["location", "observation_date", "satellite_source"],
name="ndvi_unique_location_date_source",
)
]
verbose_name = "NDVI Observation"
verbose_name_plural = "NDVI Observations"
def __str__(self):
return f"NDVI {self.location_id} {self.observation_date} {self.satellite_source}"