Files
Backend/crop_zoning/models.py
T
2026-03-30 23:29:03 +03:30

228 lines
6.7 KiB
Python

import uuid
from django.db import models
from sensor_hub.models import Sensor
class CropArea(models.Model):
uuid = models.UUIDField(default=uuid.uuid4, unique=True, editable=False, db_index=True)
sensor = models.ForeignKey(
Sensor,
on_delete=models.CASCADE,
related_name="crop_areas",
null=True,
blank=True,
db_index=True,
)
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):
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"),
)
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()
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="")
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
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"]