This commit is contained in:
2026-05-11 04:38:44 +03:30
parent 17628f503f
commit c2b6052e5c
69 changed files with 3073 additions and 57 deletions
+128
View File
@@ -3,9 +3,12 @@ from rest_framework import serializers
from .models import (
AnalysisGridObservation,
BlockSubdivision,
RemoteSensingClusterBlock,
RemoteSensingRun,
RemoteSensingClusterAssignment,
RemoteSensingSubdivisionResult,
RemoteSensingSubdivisionOption,
RemoteSensingSubdivisionOptionBlock,
SoilLocation,
)
from .satellite_snapshot import build_location_block_satellite_snapshots
@@ -141,6 +144,25 @@ class RemoteSensingFarmRequestSerializer(serializers.Serializer):
page_size = serializers.IntegerField(required=False, min_value=1, max_value=200, default=100)
class RemoteSensingClusterBlockLiveRequestSerializer(serializers.Serializer):
temporal_start = serializers.DateField(required=False)
temporal_end = serializers.DateField(required=False)
days = serializers.IntegerField(required=False, min_value=1, max_value=90, default=30)
def validate(self, attrs):
temporal_start = attrs.get("temporal_start")
temporal_end = attrs.get("temporal_end")
if bool(temporal_start) != bool(temporal_end):
raise serializers.ValidationError(
"برای بازه سفارشی باید هر دو فیلد temporal_start و temporal_end ارسال شوند."
)
if temporal_start and temporal_end and temporal_start > temporal_end:
raise serializers.ValidationError(
{"temporal_start": ["temporal_start نمی‌تواند بعد از temporal_end باشد."]}
)
return attrs
class RemoteSensingCellObservationSerializer(serializers.ModelSerializer):
cell_code = serializers.CharField(source="cell.cell_code", read_only=True)
block_code = serializers.CharField(source="cell.block_code", read_only=True)
@@ -175,6 +197,13 @@ class RemoteSensingSummarySerializer(serializers.Serializer):
soil_vv_db_mean = serializers.FloatField(allow_null=True)
class RemoteSensingClusterBlockLiveMetricsSerializer(serializers.Serializer):
ndvi = serializers.FloatField(allow_null=True)
ndwi = serializers.FloatField(allow_null=True)
soil_vv = serializers.FloatField(allow_null=True)
soil_vv_db = serializers.FloatField(allow_null=True)
class RemoteSensingRunSerializer(serializers.ModelSerializer):
status_label = serializers.SerializerMethodField()
pipeline_status = serializers.SerializerMethodField()
@@ -239,8 +268,74 @@ class RemoteSensingClusterAssignmentSerializer(serializers.ModelSerializer):
]
class RemoteSensingClusterBlockSerializer(serializers.ModelSerializer):
class Meta:
model = RemoteSensingClusterBlock
fields = [
"uuid",
"sub_block_code",
"cluster_label",
"chunk_size_sqm",
"centroid_lat",
"centroid_lon",
"center_cell_code",
"center_cell_lat",
"center_cell_lon",
"cell_count",
"cell_codes",
"geometry",
"metadata",
"created_at",
"updated_at",
]
class RemoteSensingSubdivisionOptionBlockSerializer(serializers.ModelSerializer):
class Meta:
model = RemoteSensingSubdivisionOptionBlock
fields = [
"cluster_label",
"sub_block_code",
"chunk_size_sqm",
"centroid_lat",
"centroid_lon",
"center_cell_code",
"center_cell_lat",
"center_cell_lon",
"cell_count",
"cell_codes",
"geometry",
"metadata",
]
class RemoteSensingSubdivisionOptionSerializer(serializers.ModelSerializer):
cluster_blocks = RemoteSensingSubdivisionOptionBlockSerializer(many=True, read_only=True)
class Meta:
model = RemoteSensingSubdivisionOption
fields = [
"id",
"requested_k",
"effective_cluster_count",
"is_active",
"is_recommended",
"selection_source",
"metadata",
"cluster_blocks",
"created_at",
"updated_at",
]
class RemoteSensingSubdivisionOptionActivateSerializer(serializers.Serializer):
requested_k = serializers.IntegerField(min_value=1)
class RemoteSensingSubdivisionResultSerializer(serializers.ModelSerializer):
assignments = serializers.SerializerMethodField()
cluster_blocks = RemoteSensingClusterBlockSerializer(many=True, read_only=True)
available_k_options = serializers.SerializerMethodField()
def get_assignments(self, obj):
assignments = self.context.get("paginated_assignments")
@@ -248,6 +343,10 @@ class RemoteSensingSubdivisionResultSerializer(serializers.ModelSerializer):
assignments = obj.assignments.all().order_by("cluster_label", "cell__cell_code")
return RemoteSensingClusterAssignmentSerializer(assignments, many=True).data
def get_available_k_options(self, obj):
options = obj.options.all().order_by("requested_k")
return RemoteSensingSubdivisionOptionSerializer(options, many=True).data
class Meta:
model = RemoteSensingSubdivisionResult
fields = [
@@ -260,6 +359,8 @@ class RemoteSensingSubdivisionResultSerializer(serializers.ModelSerializer):
"selected_features",
"skipped_cell_codes",
"metadata",
"available_k_options",
"cluster_blocks",
"assignments",
"created_at",
"updated_at",
@@ -309,3 +410,30 @@ class RemoteSensingRunResultResponseSerializer(serializers.Serializer):
run = RemoteSensingRunSerializer()
subdivision_result = RemoteSensingSubdivisionResultSerializer(allow_null=True)
pagination = serializers.JSONField(required=False)
class RemoteSensingClusterBlockLiveResponseSerializer(serializers.Serializer):
status = serializers.CharField()
source = serializers.CharField()
cluster_block = RemoteSensingClusterBlockSerializer()
temporal_extent = serializers.JSONField()
selected_features = serializers.ListField(
child=serializers.CharField(),
allow_empty=False,
)
summary = RemoteSensingSummarySerializer()
metrics = RemoteSensingClusterBlockLiveMetricsSerializer()
metadata = serializers.JSONField()
class RemoteSensingSubdivisionOptionListResponseSerializer(serializers.Serializer):
result_id = serializers.IntegerField()
active_requested_k = serializers.IntegerField(allow_null=True)
recommended_requested_k = serializers.IntegerField(allow_null=True)
options = RemoteSensingSubdivisionOptionSerializer(many=True)
class RemoteSensingSubdivisionOptionActivateResponseSerializer(serializers.Serializer):
result_id = serializers.IntegerField()
activated_requested_k = serializers.IntegerField()
subdivision_result = RemoteSensingSubdivisionResultSerializer()