Files

225 lines
6.7 KiB
Python
Raw Permalink Normal View History

2026-03-29 13:40:23 +03:30
import uuid
from django.db import models
2026-04-02 23:25:39 +03:30
from farm_hub.models import FarmHub
2026-03-29 13:40:23 +03:30
class CropArea(models.Model):
uuid = models.UUIDField(default=uuid.uuid4, unique=True, editable=False, db_index=True)
2026-04-02 23:25:39 +03:30
farm = models.ForeignKey(
FarmHub,
2026-03-30 23:29:03 +03:30
on_delete=models.CASCADE,
related_name="crop_areas",
null=True,
blank=True,
db_index=True,
)
2026-03-29 13:40:23 +03:30
geometry = models.JSONField(default=dict)
points = models.JSONField(default=list)
center = models.JSONField(default=dict)
area_sqm = models.FloatField()
area_hectares = models.FloatField()
chunk_area_sqm = models.FloatField()
zone_count = models.PositiveIntegerField(default=0)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = "crop_areas"
ordering = ["-created_at", "-id"]
def __str__(self):
return f"Area {self.uuid}"
class CropZone(models.Model):
2026-03-29 15:07:14 +03:30
STATUS_PENDING = "pending"
STATUS_PROCESSING = "processing"
STATUS_COMPLETED = "completed"
STATUS_FAILED = "failed"
STATUS_CHOICES = (
(STATUS_PENDING, "Pending"),
(STATUS_PROCESSING, "Processing"),
(STATUS_COMPLETED, "Completed"),
(STATUS_FAILED, "Failed"),
)
2026-03-29 13:40:23 +03:30
uuid = models.UUIDField(default=uuid.uuid4, unique=True, editable=False, db_index=True)
crop_area = models.ForeignKey(
CropArea,
on_delete=models.CASCADE,
related_name="zones",
)
zone_id = models.CharField(max_length=64)
geometry = models.JSONField(default=dict)
points = models.JSONField(default=list)
center = models.JSONField(default=dict)
area_sqm = models.FloatField()
area_hectares = models.FloatField()
sequence = models.PositiveIntegerField()
2026-03-29 15:07:14 +03:30
processing_status = models.CharField(max_length=16, choices=STATUS_CHOICES, default=STATUS_PENDING)
processing_error = models.TextField(blank=True, default="")
task_id = models.CharField(max_length=255, blank=True, default="")
2026-03-29 13:40:23 +03:30
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = "crop_zones"
ordering = ["sequence", "id"]
constraints = [
models.UniqueConstraint(fields=["crop_area", "zone_id"], name="unique_crop_area_zone_id"),
]
def __str__(self):
return self.zone_id
2026-03-29 15:07:14 +03:30
class CropProduct(models.Model):
product_id = models.CharField(max_length=64, unique=True)
label = models.CharField(max_length=255)
color = models.CharField(max_length=32)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = "crop_products"
ordering = ["id"]
def __str__(self):
return self.label
class CropZoneRecommendation(models.Model):
crop_zone = models.OneToOneField(
CropZone,
on_delete=models.CASCADE,
related_name="recommendation",
)
product = models.ForeignKey(
CropProduct,
on_delete=models.PROTECT,
related_name="zone_recommendations",
)
match_percent = models.PositiveIntegerField()
water_need = models.CharField(max_length=128)
estimated_profit = models.CharField(max_length=128)
reason = models.TextField(blank=True, default="")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = "crop_zone_recommendations"
ordering = ["crop_zone_id"]
def __str__(self):
return f"{self.crop_zone.zone_id} -> {self.product.product_id}"
class CropZoneCriteria(models.Model):
recommendation = models.ForeignKey(
CropZoneRecommendation,
on_delete=models.CASCADE,
related_name="criteria",
)
name = models.CharField(max_length=128)
value = models.PositiveIntegerField()
sequence = models.PositiveIntegerField(default=0)
class Meta:
db_table = "crop_zone_criteria"
ordering = ["sequence", "id"]
def __str__(self):
return f"{self.name}: {self.value}"
class CropZoneWaterNeedLayer(models.Model):
LEVEL_LOW = "low"
LEVEL_MEDIUM = "medium"
LEVEL_HIGH = "high"
LEVEL_CHOICES = (
(LEVEL_LOW, "Low"),
(LEVEL_MEDIUM, "Medium"),
(LEVEL_HIGH, "High"),
)
crop_zone = models.OneToOneField(
CropZone,
on_delete=models.CASCADE,
related_name="water_need_layer",
)
level = models.CharField(max_length=16, choices=LEVEL_CHOICES)
value = models.CharField(max_length=128)
color = models.CharField(max_length=32)
class Meta:
db_table = "crop_zone_water_need_layers"
ordering = ["crop_zone_id"]
class CropZoneSoilQualityLayer(models.Model):
LEVEL_LOW = "low"
LEVEL_MEDIUM = "medium"
LEVEL_HIGH = "high"
LEVEL_CHOICES = (
(LEVEL_LOW, "Low"),
(LEVEL_MEDIUM, "Medium"),
(LEVEL_HIGH, "High"),
)
crop_zone = models.OneToOneField(
CropZone,
on_delete=models.CASCADE,
related_name="soil_quality_layer",
)
level = models.CharField(max_length=16, choices=LEVEL_CHOICES)
score = models.PositiveIntegerField()
color = models.CharField(max_length=32)
class Meta:
db_table = "crop_zone_soil_quality_layers"
ordering = ["crop_zone_id"]
class CropZoneCultivationRiskLayer(models.Model):
LEVEL_LOW = "low"
LEVEL_MEDIUM = "medium"
LEVEL_HIGH = "high"
LEVEL_CHOICES = (
(LEVEL_LOW, "Low"),
(LEVEL_MEDIUM, "Medium"),
(LEVEL_HIGH, "High"),
)
crop_zone = models.OneToOneField(
CropZone,
on_delete=models.CASCADE,
related_name="cultivation_risk_layer",
)
level = models.CharField(max_length=16, choices=LEVEL_CHOICES)
color = models.CharField(max_length=32)
class Meta:
db_table = "crop_zone_cultivation_risk_layers"
ordering = ["crop_zone_id"]
class CropZoneAnalysis(models.Model):
source = models.CharField(max_length=64, blank=True, default="")
external_record_id = models.CharField(max_length=64, blank=True, default="")
latitude = models.DecimalField(max_digits=10, decimal_places=6, null=True, blank=True)
longitude = models.DecimalField(max_digits=10, decimal_places=6, null=True, blank=True)
raw_response = models.JSONField(default=dict, blank=True)
depths = models.JSONField(default=list, blank=True)
crop_zone = models.OneToOneField(
CropZone,
on_delete=models.CASCADE,
related_name="analysis",
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = "crop_zone_analyses"
ordering = ["crop_zone_id"]