Files

534 lines
37 KiB
Python
Raw Permalink Normal View History

2026-05-13 16:45:54 +03:30
from __future__ import annotations
from datetime import date, datetime
from decimal import Decimal
from uuid import UUID
from django.core.management.base import BaseCommand
from django.db import transaction
from django.utils.dateparse import parse_datetime
from location_data.models import (
AnalysisGridCell,
AnalysisGridObservation,
BlockSubdivision,
NdviObservation,
RemoteSensingClusterAssignment,
RemoteSensingClusterBlock,
RemoteSensingRun,
RemoteSensingSubdivisionOption,
RemoteSensingSubdivisionOptionAssignment,
RemoteSensingSubdivisionOptionBlock,
RemoteSensingSubdivisionResult,
SoilLocation,
)
SEED_DATA = {
"soillocations": [
{
"id": 1,
"latitude": "50.000000",
"longitude": "50.000000",
"task_id": "",
"farm_boundary": {
"type": "Polygon",
"coordinates": [[[49.9995, 49.9995], [50.0005, 49.9995], [50.0005, 50.0005], [49.9995, 50.0005], [49.9995, 49.9995]]],
},
"input_block_count": 1,
"block_layout": {
"blocks": [
{
"order": 1,
"source": "default",
"boundary": {},
"block_code": "block-1",
"sub_blocks": [],
"needs_subdivision": None,
},
{
"order": 2,
"source": "remote_sensing",
"block_code": "",
"sub_blocks": [
{
"geometry": {"type": "Polygon", "coordinates": [[[49.9995, 49.9995], [49.99992, 49.9995], [50.000339, 49.9995], [50.000339, 49.99977], [50.000339, 50.00004], [49.99992, 50.00004], [49.9995, 50.00004], [49.9995, 49.99977], [49.9995, 49.9995]]]},
"metadata": {"source": "analysis_grid_cells", "center_selection": {"strategy": "coordinate_1_center", "center_radius": 0.0004993, "center_cell_code": "loc-1__block-farm__chunk-900__r0000c0000", "center_mean_distance": 0.00029732}, "cell_geometry_type": "Polygon"},
"cell_count": 4,
"centroid_lat": 49.99977,
"centroid_lon": 49.99992,
"cluster_uuid": "daa278cb-cf75-4f17-bc94-bb3a780dd4d4",
"cluster_label": 0,
"sub_block_code": "cluster-0",
"center_cell_lat": 49.999635,
"center_cell_lon": 49.99971,
"center_cell_code": "loc-1__block-farm__chunk-900__r0000c0000",
},
{
"geometry": {"type": "Polygon", "coordinates": [[[50.000339, 49.9995], [50.000759, 49.9995], [50.000759, 49.99977], [50.000759, 50.00004], [50.000759, 50.000309], [50.000759, 50.000579], [50.000339, 50.000579], [49.99992, 50.000579], [49.9995, 50.000579], [49.9995, 50.000309], [49.9995, 50.00004], [49.99992, 50.00004], [50.000339, 50.00004], [50.000339, 49.99977], [50.000339, 49.9995]]]},
"metadata": {"source": "analysis_grid_cells", "center_selection": {"strategy": "coordinate_1_center", "center_radius": 0.0006827, "center_cell_code": "loc-1__block-farm__chunk-900__r0002c0001", "center_mean_distance": 0.00041092}, "cell_geometry_type": "Polygon"},
"cell_count": 8,
"centroid_lat": 50.000174,
"centroid_lon": 50.000235,
"cluster_uuid": "e9beea1c-8736-4c45-ac5b-f186705bad76",
"cluster_label": 1,
"sub_block_code": "cluster-1",
"center_cell_lat": 50.000174,
"center_cell_lon": 50.00013,
"center_cell_code": "loc-1__block-farm__chunk-900__r0002c0001",
},
],
"needs_subdivision": True,
"subdivision_summary": {
"type": "data_driven_remote_sensing",
"run_id": 1,
"cluster_count": 2,
"used_cell_count": 12,
"selected_features": ["ndvi", "ndwi", "soil_vv_db"],
"skipped_cell_count": 0,
},
},
],
"algorithm_status": "completed",
"default_full_farm": True,
"input_block_count": 1,
"analysis_grid_summary": {"cell_count": 12, "chunk_size_sqm": 900},
},
"created_at": "2026-05-11T14:41:43.319380+00:00",
"updated_at": "2026-05-12T12:37:38.239904+00:00",
}
],
"blocksubdivisions": [],
"remotesensingruns": [
{
"id": 1,
"soil_location_id": 1,
"block_subdivision_id": None,
"block_code": "",
"provider": "openeo",
"chunk_size_sqm": 900,
"temporal_start": "2026-04-11",
"temporal_end": "2026-05-11",
"status": "success",
"metadata": {"farm_uuid": "11111111-1111-1111-1111-111111111111", "requested_via": "api", "scope": "all_blocks"},
"error_message": "",
"started_at": "2026-05-12T12:19:03.911826+00:00",
"finished_at": "2026-05-12T12:37:39.018428+00:00",
"created_at": "2026-05-12T12:19:03.912346+00:00",
"updated_at": "2026-05-12T12:37:39.019007+00:00",
}
],
"remotesensingsubdivisionresults": [
{
"id": 1,
"soil_location_id": 1,
"run_id": 1,
"block_subdivision_id": None,
"block_code": "",
"chunk_size_sqm": 900,
"temporal_start": "2026-04-11",
"temporal_end": "2026-05-11",
"cluster_count": 2,
"selected_features": ["ndvi", "ndwi", "soil_vv_db"],
"skipped_cell_codes": [],
"metadata": {"selection_strategy": "elbow", "used_cell_count": 12},
"created_at": "2026-05-12T12:37:27.897155+00:00",
"updated_at": "2026-05-12T12:37:27.897180+00:00",
}
],
"remotesensingclusterblocks": [
{
"id": 1,
"uuid": "daa278cb-cf75-4f17-bc94-bb3a780dd4d4",
"result_id": 1,
"soil_location_id": 1,
"block_subdivision_id": None,
"block_code": "",
"sub_block_code": "cluster-0",
"cluster_label": 0,
"chunk_size_sqm": 900,
"centroid_lat": "49.999770",
"centroid_lon": "49.999920",
"center_cell_code": "loc-1__block-farm__chunk-900__r0000c0000",
"center_cell_lat": "49.999635",
"center_cell_lon": "49.999710",
"geometry": {"type": "Polygon", "coordinates": [[[49.9995, 49.9995], [49.99992, 49.9995], [50.000339, 49.9995], [50.000339, 49.99977], [50.000339, 50.00004], [49.99992, 50.00004], [49.9995, 50.00004], [49.9995, 49.99977], [49.9995, 49.9995]]]},
"cell_count": 4,
"cell_codes": ["loc-1__block-farm__chunk-900__r0000c0000", "loc-1__block-farm__chunk-900__r0000c0001", "loc-1__block-farm__chunk-900__r0001c0000", "loc-1__block-farm__chunk-900__r0001c0001"],
"metadata": {"source": "analysis_grid_cells"},
"created_at": "2026-05-12T12:37:27.899874+00:00",
"updated_at": "2026-05-12T12:37:27.899899+00:00",
},
{
"id": 2,
"uuid": "e9beea1c-8736-4c45-ac5b-f186705bad76",
"result_id": 1,
"soil_location_id": 1,
"block_subdivision_id": None,
"block_code": "",
"sub_block_code": "cluster-1",
"cluster_label": 1,
"chunk_size_sqm": 900,
"centroid_lat": "50.000174",
"centroid_lon": "50.000235",
"center_cell_code": "loc-1__block-farm__chunk-900__r0002c0001",
"center_cell_lat": "50.000174",
"center_cell_lon": "50.000130",
"geometry": {"type": "Polygon", "coordinates": [[[50.000339, 49.9995], [50.000759, 49.9995], [50.000759, 49.99977], [50.000759, 50.00004], [50.000759, 50.000309], [50.000759, 50.000579], [50.000339, 50.000579], [49.99992, 50.000579], [49.9995, 50.000579], [49.9995, 50.000309], [49.9995, 50.00004], [49.99992, 50.00004], [50.000339, 50.00004], [50.000339, 49.99977], [50.000339, 49.9995]]]},
"cell_count": 8,
"cell_codes": ["loc-1__block-farm__chunk-900__r0000c0002", "loc-1__block-farm__chunk-900__r0001c0002", "loc-1__block-farm__chunk-900__r0002c0000", "loc-1__block-farm__chunk-900__r0002c0001", "loc-1__block-farm__chunk-900__r0002c0002", "loc-1__block-farm__chunk-900__r0003c0000", "loc-1__block-farm__chunk-900__r0003c0001", "loc-1__block-farm__chunk-900__r0003c0002"],
"metadata": {"source": "analysis_grid_cells"},
"created_at": "2026-05-12T12:37:27.901926+00:00",
"updated_at": "2026-05-12T12:37:27.901945+00:00",
},
],
"analysisgridcells": [
{"id": 1, "soil_location_id": 1, "block_subdivision_id": None, "block_code": "", "cell_code": "loc-1__block-farm__chunk-900__r0000c0000", "chunk_size_sqm": 900, "geometry": {"type": "Polygon", "coordinates": [[[49.9995, 49.9995], [49.99992, 49.9995], [49.99992, 49.99977], [49.9995, 49.99977], [49.9995, 49.9995]]]}, "centroid_lat": "49.999635", "centroid_lon": "49.999710", "created_at": "2026-05-12T12:19:03.930590+00:00", "updated_at": "2026-05-12T12:19:03.930609+00:00"},
{"id": 2, "soil_location_id": 1, "block_subdivision_id": None, "block_code": "", "cell_code": "loc-1__block-farm__chunk-900__r0000c0001", "chunk_size_sqm": 900, "geometry": {"type": "Polygon", "coordinates": [[[49.99992, 49.9995], [50.000339, 49.9995], [50.000339, 49.99977], [49.99992, 49.99977], [49.99992, 49.9995]]]}, "centroid_lat": "49.999635", "centroid_lon": "50.000130", "created_at": "2026-05-12T12:19:03.931797+00:00", "updated_at": "2026-05-12T12:19:03.931817+00:00"},
{"id": 3, "soil_location_id": 1, "block_subdivision_id": None, "block_code": "", "cell_code": "loc-1__block-farm__chunk-900__r0000c0002", "chunk_size_sqm": 900, "geometry": {"type": "Polygon", "coordinates": [[[50.000339, 49.9995], [50.000759, 49.9995], [50.000759, 49.99977], [50.000339, 49.99977], [50.000339, 49.9995]]]}, "centroid_lat": "49.999635", "centroid_lon": "50.000549", "created_at": "2026-05-12T12:19:03.931857+00:00", "updated_at": "2026-05-12T12:19:03.931864+00:00"},
{"id": 4, "soil_location_id": 1, "block_subdivision_id": None, "block_code": "", "cell_code": "loc-1__block-farm__chunk-900__r0001c0000", "chunk_size_sqm": 900, "geometry": {"type": "Polygon", "coordinates": [[[49.9995, 49.99977], [49.99992, 49.99977], [49.99992, 50.00004], [49.9995, 50.00004], [49.9995, 49.99977]]]}, "centroid_lat": "49.999905", "centroid_lon": "49.999710", "created_at": "2026-05-12T12:19:03.931899+00:00", "updated_at": "2026-05-12T12:19:03.931906+00:00"},
{"id": 5, "soil_location_id": 1, "block_subdivision_id": None, "block_code": "", "cell_code": "loc-1__block-farm__chunk-900__r0001c0001", "chunk_size_sqm": 900, "geometry": {"type": "Polygon", "coordinates": [[[49.99992, 49.99977], [50.000339, 49.99977], [50.000339, 50.00004], [49.99992, 50.00004], [49.99992, 49.99977]]]}, "centroid_lat": "49.999905", "centroid_lon": "50.000130", "created_at": "2026-05-12T12:19:03.931939+00:00", "updated_at": "2026-05-12T12:19:03.931945+00:00"},
{"id": 6, "soil_location_id": 1, "block_subdivision_id": None, "block_code": "", "cell_code": "loc-1__block-farm__chunk-900__r0001c0002", "chunk_size_sqm": 900, "geometry": {"type": "Polygon", "coordinates": [[[50.000339, 49.99977], [50.000759, 49.99977], [50.000759, 50.00004], [50.000339, 50.00004], [50.000339, 49.99977]]]}, "centroid_lat": "49.999905", "centroid_lon": "50.000549", "created_at": "2026-05-12T12:19:03.931978+00:00", "updated_at": "2026-05-12T12:19:03.931985+00:00"},
{"id": 7, "soil_location_id": 1, "block_subdivision_id": None, "block_code": "", "cell_code": "loc-1__block-farm__chunk-900__r0002c0000", "chunk_size_sqm": 900, "geometry": {"type": "Polygon", "coordinates": [[[49.9995, 50.00004], [49.99992, 50.00004], [49.99992, 50.000309], [49.9995, 50.000309], [49.9995, 50.00004]]]}, "centroid_lat": "50.000174", "centroid_lon": "49.999710", "created_at": "2026-05-12T12:19:03.932017+00:00", "updated_at": "2026-05-12T12:19:03.932024+00:00"},
{"id": 8, "soil_location_id": 1, "block_subdivision_id": None, "block_code": "", "cell_code": "loc-1__block-farm__chunk-900__r0002c0001", "chunk_size_sqm": 900, "geometry": {"type": "Polygon", "coordinates": [[[49.99992, 50.00004], [50.000339, 50.00004], [50.000339, 50.000309], [49.99992, 50.000309], [49.99992, 50.00004]]]}, "centroid_lat": "50.000174", "centroid_lon": "50.000130", "created_at": "2026-05-12T12:19:03.932056+00:00", "updated_at": "2026-05-12T12:19:03.932063+00:00"},
{"id": 9, "soil_location_id": 1, "block_subdivision_id": None, "block_code": "", "cell_code": "loc-1__block-farm__chunk-900__r0002c0002", "chunk_size_sqm": 900, "geometry": {"type": "Polygon", "coordinates": [[[50.000339, 50.00004], [50.000759, 50.00004], [50.000759, 50.000309], [50.000339, 50.000309], [50.000339, 50.00004]]]}, "centroid_lat": "50.000174", "centroid_lon": "50.000549", "created_at": "2026-05-12T12:19:03.932100+00:00", "updated_at": "2026-05-12T12:19:03.932107+00:00"},
{"id": 10, "soil_location_id": 1, "block_subdivision_id": None, "block_code": "", "cell_code": "loc-1__block-farm__chunk-900__r0003c0000", "chunk_size_sqm": 900, "geometry": {"type": "Polygon", "coordinates": [[[49.9995, 50.000309], [49.99992, 50.000309], [49.99992, 50.000579], [49.9995, 50.000579], [49.9995, 50.000309]]]}, "centroid_lat": "50.000444", "centroid_lon": "49.999710", "created_at": "2026-05-12T12:19:03.932145+00:00", "updated_at": "2026-05-12T12:19:03.932152+00:00"},
{"id": 11, "soil_location_id": 1, "block_subdivision_id": None, "block_code": "", "cell_code": "loc-1__block-farm__chunk-900__r0003c0001", "chunk_size_sqm": 900, "geometry": {"type": "Polygon", "coordinates": [[[49.99992, 50.000309], [50.000339, 50.000309], [50.000339, 50.000579], [49.99992, 50.000579], [49.99992, 50.000309]]]}, "centroid_lat": "50.000444", "centroid_lon": "50.000130", "created_at": "2026-05-12T12:19:03.932191+00:00", "updated_at": "2026-05-12T12:19:03.932198+00:00"},
{"id": 12, "soil_location_id": 1, "block_subdivision_id": None, "block_code": "", "cell_code": "loc-1__block-farm__chunk-900__r0003c0002", "chunk_size_sqm": 900, "geometry": {"type": "Polygon", "coordinates": [[[50.000339, 50.000309], [50.000759, 50.000309], [50.000759, 50.000579], [50.000339, 50.000579], [50.000339, 50.000309]]]}, "centroid_lat": "50.000444", "centroid_lon": "50.000549", "created_at": "2026-05-12T12:19:03.932234+00:00", "updated_at": "2026-05-12T12:19:03.932241+00:00"},
],
"analysisgridobservations": [
{"id": 1, "cell_id": 1, "run_id": 1, "temporal_start": "2026-04-11", "temporal_end": "2026-05-11", "ndvi": 0.6483580933676826, "ndwi": -0.5629512800110711, "soil_vv": -15.369688, "soil_vv_db": -15.369688, "dem_m": None, "slope_deg": None, "metadata": {}, "created_at": "2026-05-12T12:37:26.614257+00:00", "updated_at": "2026-05-12T12:37:26.614281+00:00"},
{"id": 2, "cell_id": 2, "run_id": 1, "temporal_start": "2026-04-11", "temporal_end": "2026-05-11", "ndvi": 0.6588515573077731, "ndwi": -0.5730775992075602, "soil_vv": -14.043169, "soil_vv_db": -14.043169, "dem_m": None, "slope_deg": None, "metadata": {}, "created_at": "2026-05-12T12:37:26.615124+00:00", "updated_at": "2026-05-12T12:37:26.615143+00:00"},
{"id": 3, "cell_id": 3, "run_id": 1, "temporal_start": "2026-04-11", "temporal_end": "2026-05-11", "ndvi": 0.6946650213665433, "ndwi": -0.6026291714774238, "soil_vv": -13.727797, "soil_vv_db": -13.727797, "dem_m": None, "slope_deg": None, "metadata": {}, "created_at": "2026-05-12T12:37:26.615867+00:00", "updated_at": "2026-05-12T12:37:26.615885+00:00"},
{"id": 4, "cell_id": 4, "run_id": 1, "temporal_start": "2026-04-11", "temporal_end": "2026-05-11", "ndvi": 0.6682408054669698, "ndwi": -0.578668495019277, "soil_vv": -13.127913, "soil_vv_db": -13.127913, "dem_m": None, "slope_deg": None, "metadata": {}, "created_at": "2026-05-12T12:37:26.616668+00:00", "updated_at": "2026-05-12T12:37:26.616687+00:00"},
{"id": 5, "cell_id": 5, "run_id": 1, "temporal_start": "2026-04-11", "temporal_end": "2026-05-11", "ndvi": 0.6642558574676514, "ndwi": -0.5712497035662333, "soil_vv": -12.400669, "soil_vv_db": -12.400669, "dem_m": None, "slope_deg": None, "metadata": {}, "created_at": "2026-05-12T12:37:26.617453+00:00", "updated_at": "2026-05-12T12:37:26.617472+00:00"},
{"id": 6, "cell_id": 6, "run_id": 1, "temporal_start": "2026-04-11", "temporal_end": "2026-05-11", "ndvi": 0.7056174145804511, "ndwi": -0.599965857134925, "soil_vv": -12.273758, "soil_vv_db": -12.273758, "dem_m": None, "slope_deg": None, "metadata": {}, "created_at": "2026-05-12T12:37:26.618181+00:00", "updated_at": "2026-05-12T12:37:26.618199+00:00"},
{"id": 7, "cell_id": 7, "run_id": 1, "temporal_start": "2026-04-11", "temporal_end": "2026-05-11", "ndvi": 0.6824584868219163, "ndwi": -0.5929381317562528, "soil_vv": -12.147284, "soil_vv_db": -12.147284, "dem_m": None, "slope_deg": None, "metadata": {}, "created_at": "2026-05-12T12:37:26.618964+00:00", "updated_at": "2026-05-12T12:37:26.618982+00:00"},
{"id": 8, "cell_id": 8, "run_id": 1, "temporal_start": "2026-04-11", "temporal_end": "2026-05-11", "ndvi": 0.6956862476136949, "ndwi": -0.6001381145583259, "soil_vv": -13.170681, "soil_vv_db": -13.170681, "dem_m": None, "slope_deg": None, "metadata": {}, "created_at": "2026-05-12T12:37:26.619733+00:00", "updated_at": "2026-05-12T12:37:26.619750+00:00"},
{"id": 9, "cell_id": 9, "run_id": 1, "temporal_start": "2026-04-11", "temporal_end": "2026-05-11", "ndvi": 0.7093238963021172, "ndwi": -0.6121659080187479, "soil_vv": -13.873331, "soil_vv_db": -13.873331, "dem_m": None, "slope_deg": None, "metadata": {}, "created_at": "2026-05-12T12:37:26.620504+00:00", "updated_at": "2026-05-12T12:37:26.620522+00:00"},
{"id": 10, "cell_id": 10, "run_id": 1, "temporal_start": "2026-04-11", "temporal_end": "2026-05-11", "ndvi": 0.6764502127965292, "ndwi": -0.5939946042166816, "soil_vv": -14.09151, "soil_vv_db": -14.09151, "dem_m": None, "slope_deg": None, "metadata": {}, "created_at": "2026-05-12T12:37:26.621257+00:00", "updated_at": "2026-05-12T12:37:26.621275+00:00"},
{"id": 11, "cell_id": 11, "run_id": 1, "temporal_start": "2026-04-11", "temporal_end": "2026-05-11", "ndvi": 0.6600760486390855, "ndwi": -0.5822326408492194, "soil_vv": -13.272252, "soil_vv_db": -13.272252, "dem_m": None, "slope_deg": None, "metadata": {}, "created_at": "2026-05-12T12:37:26.621989+00:00", "updated_at": "2026-05-12T12:37:26.622008+00:00"},
{"id": 12, "cell_id": 12, "run_id": 1, "temporal_start": "2026-04-11", "temporal_end": "2026-05-11", "ndvi": 0.6991057925754123, "ndwi": -0.6043583750724792, "soil_vv": -12.991811, "soil_vv_db": -12.991811, "dem_m": None, "slope_deg": None, "metadata": {}, "created_at": "2026-05-12T12:37:26.622751+00:00", "updated_at": "2026-05-12T12:37:26.622769+00:00"},
],
"remotesensingclusterassignments": [
{"id": 1, "result_id": 1, "cell_id": 1, "cluster_label": 0, "raw_feature_values": {"ndvi": 0.6483580933676826, "ndwi": -0.5629512800110711, "soil_vv_db": -15.369688}, "scaled_feature_values": {"ndvi": -1.630738, "ndwi": 1.792215, "soil_vv_db": -2.274005}, "created_at": "2026-05-12T12:37:27.901986+00:00", "updated_at": "2026-05-12T12:37:27.902003+00:00"},
{"id": 2, "result_id": 1, "cell_id": 2, "cluster_label": 0, "raw_feature_values": {"ndvi": 0.6588515573077731, "ndwi": -0.5730775992075602, "soil_vv_db": -14.043169}, "scaled_feature_values": {"ndvi": -1.094298, "ndwi": 1.109414, "soil_vv_db": -0.762373}, "created_at": "2026-05-12T12:37:27.902768+00:00", "updated_at": "2026-05-12T12:37:27.902786+00:00"},
{"id": 3, "result_id": 1, "cell_id": 3, "cluster_label": 1, "raw_feature_values": {"ndvi": 0.6946650213665433, "ndwi": -0.6026291714774238, "soil_vv_db": -13.727797}, "scaled_feature_values": {"ndvi": 0.736534, "ndwi": -0.8832, "soil_vv_db": -0.402992}, "created_at": "2026-05-12T12:37:27.903479+00:00", "updated_at": "2026-05-12T12:37:27.903497+00:00"},
{"id": 4, "result_id": 1, "cell_id": 4, "cluster_label": 0, "raw_feature_values": {"ndvi": 0.6682408054669698, "ndwi": -0.578668495019277, "soil_vv_db": -13.127913}, "scaled_feature_values": {"ndvi": -0.614307, "ndwi": 0.732429, "soil_vv_db": 0.280605}, "created_at": "2026-05-12T12:37:27.904197+00:00", "updated_at": "2026-05-12T12:37:27.904214+00:00"},
{"id": 5, "result_id": 1, "cell_id": 5, "cluster_label": 0, "raw_feature_values": {"ndvi": 0.6642558574676514, "ndwi": -0.5712497035662333, "soil_vv_db": -12.400669}, "scaled_feature_values": {"ndvi": -0.818023, "ndwi": 1.232666, "soil_vv_db": 1.109334}, "created_at": "2026-05-12T12:37:27.904909+00:00", "updated_at": "2026-05-12T12:37:27.904926+00:00"},
{"id": 6, "result_id": 1, "cell_id": 6, "cluster_label": 1, "raw_feature_values": {"ndvi": 0.7056174145804511, "ndwi": -0.599965857134925, "soil_vv_db": -12.273758}, "scaled_feature_values": {"ndvi": 1.296436, "ndwi": -0.703617, "soil_vv_db": 1.253955}, "created_at": "2026-05-12T12:37:27.905606+00:00", "updated_at": "2026-05-12T12:37:27.905623+00:00"},
{"id": 7, "result_id": 1, "cell_id": 7, "cluster_label": 1, "raw_feature_values": {"ndvi": 0.6824584868219163, "ndwi": -0.5929381317562528, "soil_vv_db": -12.147284}, "scaled_feature_values": {"ndvi": 0.11252, "ndwi": -0.229749, "soil_vv_db": 1.398079}, "created_at": "2026-05-12T12:37:27.906325+00:00", "updated_at": "2026-05-12T12:37:27.906343+00:00"},
{"id": 8, "result_id": 1, "cell_id": 8, "cluster_label": 1, "raw_feature_values": {"ndvi": 0.6956862476136949, "ndwi": -0.6001381145583259, "soil_vv_db": -13.170681}, "scaled_feature_values": {"ndvi": 0.788741, "ndwi": -0.715232, "soil_vv_db": 0.231869}, "created_at": "2026-05-12T12:37:27.907052+00:00", "updated_at": "2026-05-12T12:37:27.907069+00:00"},
{"id": 9, "result_id": 1, "cell_id": 9, "cluster_label": 1, "raw_feature_values": {"ndvi": 0.7093238963021172, "ndwi": -0.6121659080187479, "soil_vv_db": -13.873331}, "scaled_feature_values": {"ndvi": 1.485916, "ndwi": -1.526247, "soil_vv_db": -0.568835}, "created_at": "2026-05-12T12:37:27.907735+00:00", "updated_at": "2026-05-12T12:37:27.907752+00:00"},
{"id": 10, "result_id": 1, "cell_id": 10, "cluster_label": 1, "raw_feature_values": {"ndvi": 0.6764502127965292, "ndwi": -0.5939946042166816, "soil_vv_db": -14.09151}, "scaled_feature_values": {"ndvi": -0.194631, "ndwi": -0.300985, "soil_vv_db": -0.81746}, "created_at": "2026-05-12T12:37:27.908441+00:00", "updated_at": "2026-05-12T12:37:27.908458+00:00"},
{"id": 11, "result_id": 1, "cell_id": 11, "cluster_label": 1, "raw_feature_values": {"ndvi": 0.6600760486390855, "ndwi": -0.5822326408492194, "soil_vv_db": -13.272252}, "scaled_feature_values": {"ndvi": -1.031701, "ndwi": 0.492105, "soil_vv_db": 0.116124}, "created_at": "2026-05-12T12:37:27.909117+00:00", "updated_at": "2026-05-12T12:37:27.909134+00:00"},
{"id": 12, "result_id": 1, "cell_id": 12, "cluster_label": 1, "raw_feature_values": {"ndvi": 0.6991057925754123, "ndwi": -0.6043583750724792, "soil_vv_db": -12.991811}, "scaled_feature_values": {"ndvi": 0.963553, "ndwi": -0.999798, "soil_vv_db": 0.4357}, "created_at": "2026-05-12T12:37:27.909828+00:00", "updated_at": "2026-05-12T12:37:27.909845+00:00"},
],
"remotesensingsubdivisionoptions": [],
"remotesensingsubdivisionoptionblocks": [],
"remotesensingsubdivisionoptionassignments": [],
"ndviobservations": [],
}
def _dt(value: str | None):
if not value:
return None
parsed = parse_datetime(value)
if parsed is not None:
return parsed
return datetime.fromisoformat(value)
def _date(value: str | None):
if not value:
return None
return date.fromisoformat(value)
def _decimal(value):
if value is None:
return None
return Decimal(str(value))
def _uuid(value):
if not value:
return None
return UUID(str(value))
class Command(BaseCommand):
help = "Seed the current location_data database snapshot into local tables."
def add_arguments(self, parser):
parser.add_argument(
"--flush-existing",
action="store_true",
help="Delete existing location_data seeded tables before inserting the snapshot.",
)
@transaction.atomic
def handle(self, *args, **options):
if options["flush_existing"]:
self._flush_existing()
self._seed_soil_locations()
self._seed_block_subdivisions()
self._seed_remote_sensing_runs()
self._seed_subdivision_results()
self._seed_cluster_blocks()
self._seed_analysis_grid_cells()
self._seed_analysis_grid_observations()
self._seed_cluster_assignments()
self._seed_subdivision_options()
self._seed_subdivision_option_blocks()
self._seed_subdivision_option_assignments()
self._seed_ndvi_observations()
self.stdout.write(self.style.SUCCESS("location_data seed snapshot applied successfully."))
def _flush_existing(self):
RemoteSensingSubdivisionOptionAssignment.objects.all().delete()
RemoteSensingSubdivisionOptionBlock.objects.all().delete()
RemoteSensingSubdivisionOption.objects.all().delete()
RemoteSensingClusterAssignment.objects.all().delete()
AnalysisGridObservation.objects.all().delete()
RemoteSensingClusterBlock.objects.all().delete()
RemoteSensingSubdivisionResult.objects.all().delete()
RemoteSensingRun.objects.all().delete()
AnalysisGridCell.objects.all().delete()
BlockSubdivision.objects.all().delete()
NdviObservation.objects.all().delete()
SoilLocation.objects.all().delete()
def _seed_soil_locations(self):
for row in SEED_DATA["soillocations"]:
obj, _ = SoilLocation.objects.update_or_create(
id=row["id"],
defaults={
"latitude": _decimal(row["latitude"]),
"longitude": _decimal(row["longitude"]),
"task_id": row["task_id"],
"farm_boundary": row["farm_boundary"],
"input_block_count": row["input_block_count"],
"block_layout": row["block_layout"],
},
)
self._touch(obj, row)
def _seed_block_subdivisions(self):
for row in SEED_DATA["blocksubdivisions"]:
obj, _ = BlockSubdivision.objects.update_or_create(
id=row["id"],
defaults={
"soil_location_id": row["soil_location_id"],
"block_code": row["block_code"],
"source_boundary": row["source_boundary"],
"chunk_size_sqm": row["chunk_size_sqm"],
"grid_points": row["grid_points"],
"centroid_points": row["centroid_points"],
"grid_point_count": row["grid_point_count"],
"centroid_count": row["centroid_count"],
"elbow_plot": row.get("elbow_plot", ""),
"subdivision_summary": row.get("subdivision_summary", {}),
},
)
self._touch(obj, row)
def _seed_remote_sensing_runs(self):
for row in SEED_DATA["remotesensingruns"]:
obj, _ = RemoteSensingRun.objects.update_or_create(
id=row["id"],
defaults={
"soil_location_id": row["soil_location_id"],
"block_subdivision_id": row["block_subdivision_id"],
"block_code": row["block_code"],
"provider": row["provider"],
"chunk_size_sqm": row["chunk_size_sqm"],
"temporal_start": _date(row["temporal_start"]),
"temporal_end": _date(row["temporal_end"]),
"status": row["status"],
"metadata": row["metadata"],
"error_message": row["error_message"],
"started_at": _dt(row["started_at"]),
"finished_at": _dt(row["finished_at"]),
},
)
self._touch(obj, row)
def _seed_subdivision_results(self):
for row in SEED_DATA["remotesensingsubdivisionresults"]:
obj, _ = RemoteSensingSubdivisionResult.objects.update_or_create(
id=row["id"],
defaults={
"soil_location_id": row["soil_location_id"],
"run_id": row["run_id"],
"block_subdivision_id": row["block_subdivision_id"],
"block_code": row["block_code"],
"chunk_size_sqm": row["chunk_size_sqm"],
"temporal_start": _date(row["temporal_start"]),
"temporal_end": _date(row["temporal_end"]),
"cluster_count": row["cluster_count"],
"selected_features": row["selected_features"],
"skipped_cell_codes": row["skipped_cell_codes"],
"metadata": row["metadata"],
},
)
self._touch(obj, row)
def _seed_cluster_blocks(self):
for row in SEED_DATA["remotesensingclusterblocks"]:
obj, _ = RemoteSensingClusterBlock.objects.update_or_create(
id=row["id"],
defaults={
"uuid": _uuid(row["uuid"]),
"result_id": row["result_id"],
"soil_location_id": row["soil_location_id"],
"block_subdivision_id": row["block_subdivision_id"],
"block_code": row["block_code"],
"sub_block_code": row["sub_block_code"],
"cluster_label": row["cluster_label"],
"chunk_size_sqm": row["chunk_size_sqm"],
"centroid_lat": _decimal(row["centroid_lat"]),
"centroid_lon": _decimal(row["centroid_lon"]),
"center_cell_code": row["center_cell_code"],
"center_cell_lat": _decimal(row["center_cell_lat"]),
"center_cell_lon": _decimal(row["center_cell_lon"]),
"geometry": row["geometry"],
"cell_count": row["cell_count"],
"cell_codes": row["cell_codes"],
"metadata": row["metadata"],
},
)
self._touch(obj, row)
def _seed_analysis_grid_cells(self):
for row in SEED_DATA["analysisgridcells"]:
obj, _ = AnalysisGridCell.objects.update_or_create(
id=row["id"],
defaults={
"soil_location_id": row["soil_location_id"],
"block_subdivision_id": row["block_subdivision_id"],
"block_code": row["block_code"],
"cell_code": row["cell_code"],
"chunk_size_sqm": row["chunk_size_sqm"],
"geometry": row["geometry"],
"centroid_lat": _decimal(row["centroid_lat"]),
"centroid_lon": _decimal(row["centroid_lon"]),
},
)
self._touch(obj, row)
def _seed_analysis_grid_observations(self):
for row in SEED_DATA["analysisgridobservations"]:
obj, _ = AnalysisGridObservation.objects.update_or_create(
id=row["id"],
defaults={
"cell_id": row["cell_id"],
"run_id": row["run_id"],
"temporal_start": _date(row["temporal_start"]),
"temporal_end": _date(row["temporal_end"]),
"ndvi": row["ndvi"],
"ndwi": row["ndwi"],
"soil_vv": row["soil_vv"],
"soil_vv_db": row["soil_vv_db"],
"dem_m": row["dem_m"],
"slope_deg": row["slope_deg"],
"metadata": row["metadata"],
},
)
self._touch(obj, row)
def _seed_cluster_assignments(self):
for row in SEED_DATA["remotesensingclusterassignments"]:
obj, _ = RemoteSensingClusterAssignment.objects.update_or_create(
id=row["id"],
defaults={
"result_id": row["result_id"],
"cell_id": row["cell_id"],
"cluster_label": row["cluster_label"],
"raw_feature_values": row["raw_feature_values"],
"scaled_feature_values": row["scaled_feature_values"],
},
)
self._touch(obj, row)
def _seed_subdivision_options(self):
for row in SEED_DATA["remotesensingsubdivisionoptions"]:
obj, _ = RemoteSensingSubdivisionOption.objects.update_or_create(
id=row["id"],
defaults={
"result_id": row["result_id"],
"requested_k": row["requested_k"],
"effective_cluster_count": row["effective_cluster_count"],
"is_active": row["is_active"],
"is_recommended": row["is_recommended"],
"selection_source": row["selection_source"],
"metadata": row["metadata"],
},
)
self._touch(obj, row)
def _seed_subdivision_option_blocks(self):
for row in SEED_DATA["remotesensingsubdivisionoptionblocks"]:
obj, _ = RemoteSensingSubdivisionOptionBlock.objects.update_or_create(
id=row["id"],
defaults={
"option_id": row["option_id"],
"cluster_label": row["cluster_label"],
"sub_block_code": row["sub_block_code"],
"chunk_size_sqm": row["chunk_size_sqm"],
"centroid_lat": _decimal(row["centroid_lat"]),
"centroid_lon": _decimal(row["centroid_lon"]),
"center_cell_code": row["center_cell_code"],
"center_cell_lat": _decimal(row["center_cell_lat"]),
"center_cell_lon": _decimal(row["center_cell_lon"]),
"geometry": row["geometry"],
"cell_count": row["cell_count"],
"cell_codes": row["cell_codes"],
"metadata": row["metadata"],
},
)
self._touch(obj, row)
def _seed_subdivision_option_assignments(self):
for row in SEED_DATA["remotesensingsubdivisionoptionassignments"]:
obj, _ = RemoteSensingSubdivisionOptionAssignment.objects.update_or_create(
id=row["id"],
defaults={
"option_id": row["option_id"],
"cell_id": row["cell_id"],
"cluster_label": row["cluster_label"],
"raw_feature_values": row["raw_feature_values"],
"scaled_feature_values": row["scaled_feature_values"],
},
)
self._touch(obj, row)
def _seed_ndvi_observations(self):
for row in SEED_DATA["ndviobservations"]:
obj, _ = NdviObservation.objects.update_or_create(
id=row["id"],
defaults={
"location_id": row["location_id"],
"observation_date": _date(row["observation_date"]),
"mean_ndvi": row["mean_ndvi"],
"ndvi_map": row["ndvi_map"],
"vegetation_health_class": row["vegetation_health_class"],
"satellite_source": row["satellite_source"],
"cloud_cover": row["cloud_cover"],
"metadata": row["metadata"],
},
)
self._touch(obj, row, created_field=False)
def _touch(self, obj, row, *, created_field=True):
updates = []
if created_field and hasattr(obj, "created_at") and row.get("created_at"):
obj.created_at = _dt(row["created_at"])
updates.append("created_at")
if hasattr(obj, "updated_at") and row.get("updated_at"):
obj.updated_at = _dt(row["updated_at"])
updates.append("updated_at")
if updates:
obj.save(update_fields=updates)