Files
Ai/farm_data/serializers.py
T

186 lines
6.7 KiB
Python
Raw Normal View History

2026-04-06 23:50:24 +03:30
from rest_framework import serializers
from location_data.serializers import SoilDepthDataSerializer
2026-04-24 02:50:27 +03:30
from irrigation.models import IrrigationMethod
from irrigation.serializers import IrrigationMethodSerializer
2026-04-06 23:50:24 +03:30
from plant.serializers import PlantSerializer
from weather.models import WeatherForecast
from .models import DEFAULT_SENSOR_DATA_TYPE, DEFAULT_SENSOR_KEY, SensorData
class SensorDataUpdateSerializer(serializers.Serializer):
"""ورودی آپدیت داده سنسور در ساختار JSON."""
farm_uuid = serializers.UUIDField(required=True)
farm_boundary = serializers.JSONField(required=True)
sensor_key = serializers.CharField(required=False, default=DEFAULT_SENSOR_KEY)
sensor_payload = serializers.JSONField(required=False)
plant_ids = serializers.ListField(
child=serializers.IntegerField(),
required=False,
help_text="لیست شناسه گیاهان مرتبط",
)
2026-04-24 02:50:27 +03:30
irrigation_method_id = serializers.IntegerField(
required=False,
allow_null=True,
help_text="شناسه روش آبیاری مرتبط",
)
2026-04-06 23:50:24 +03:30
def to_internal_value(self, data):
if not isinstance(data, dict):
raise serializers.ValidationError("بدنه درخواست باید JSON object باشد.")
payload = dict(data)
known_fields = {
"farm_uuid",
"farm_boundary",
"sensor_key",
"sensor_payload",
"plant_ids",
2026-04-24 02:50:27 +03:30
"irrigation_method_id",
2026-04-06 23:50:24 +03:30
}
flat_metrics = {
key: value
for key, value in payload.items()
if key not in known_fields
}
if flat_metrics:
sensor_key = payload.get("sensor_key", DEFAULT_SENSOR_KEY)
nested_payload = payload.get("sensor_payload") or {}
if nested_payload and not isinstance(nested_payload, dict):
raise serializers.ValidationError(
{"sensor_payload": "sensor_payload باید object باشد."}
)
merged_payload = dict(nested_payload)
current_sensor_payload = merged_payload.get(sensor_key, {})
if current_sensor_payload and not isinstance(current_sensor_payload, dict):
raise serializers.ValidationError(
{"sensor_payload": f"مقدار {sensor_key} باید object باشد."}
)
merged_sensor_payload = dict(current_sensor_payload)
merged_sensor_payload.update(flat_metrics)
merged_payload[sensor_key] = merged_sensor_payload
payload["sensor_payload"] = merged_payload
for key in flat_metrics:
payload.pop(key, None)
return super().to_internal_value(payload)
def validate_sensor_payload(self, value):
if not isinstance(value, dict):
raise serializers.ValidationError("sensor_payload باید object باشد.")
for sensor_key, sensor_values in value.items():
if not isinstance(sensor_values, dict):
raise serializers.ValidationError(
f"مقدار سنسور {sensor_key} باید object باشد."
)
return value
2026-04-24 02:50:27 +03:30
def validate_irrigation_method_id(self, value):
if value is None:
return value
if not IrrigationMethod.objects.filter(pk=value).exists():
raise serializers.ValidationError("روش آبیاری معتبر نیست.")
return value
2026-04-06 23:50:24 +03:30
def validate(self, attrs):
2026-04-24 02:50:27 +03:30
if (
"sensor_payload" not in attrs
and "plant_ids" not in attrs
and "irrigation_method_id" not in attrs
):
2026-04-06 23:50:24 +03:30
raise serializers.ValidationError(
2026-04-24 02:50:27 +03:30
"حداقل یکی از sensor_payload یا plant_ids یا irrigation_method_id باید ارسال شود."
2026-04-06 23:50:24 +03:30
)
return attrs
class SensorDataResponseSerializer(serializers.ModelSerializer):
"""سریالایزر خروجی برای SensorData."""
plant_ids = serializers.PrimaryKeyRelatedField(
source="plants",
many=True,
read_only=True,
)
2026-04-24 02:50:27 +03:30
irrigation_method_id = serializers.IntegerField(
source="irrigation_method.id",
read_only=True,
allow_null=True,
)
2026-04-06 23:50:24 +03:30
class Meta:
model = SensorData
fields = [
"farm_uuid",
"center_location_id",
"weather_forecast_id",
"sensor_payload",
"plant_ids",
2026-04-24 02:50:27 +03:30
"irrigation_method_id",
2026-04-06 23:50:24 +03:30
"created_at",
"updated_at",
]
class SensorParameterSerializer(serializers.Serializer):
"""سریالایزر ورودی برای تعریف پارامترهای سنسورهای مختلف."""
sensor_key = serializers.CharField(max_length=64, required=False, default=DEFAULT_SENSOR_KEY)
code = serializers.CharField(max_length=64)
name_fa = serializers.CharField(max_length=128)
unit = serializers.CharField(max_length=32, required=False, allow_blank=True)
data_type = serializers.CharField(
max_length=32,
required=False,
default=DEFAULT_SENSOR_DATA_TYPE,
)
metadata = serializers.JSONField(required=False, default=dict)
class FarmCenterLocationSerializer(serializers.Serializer):
id = serializers.IntegerField()
lat = serializers.DecimalField(max_digits=9, decimal_places=6)
lon = serializers.DecimalField(max_digits=9, decimal_places=6)
farm_boundary = serializers.JSONField()
class WeatherForecastDetailSerializer(serializers.ModelSerializer):
class Meta:
model = WeatherForecast
fields = [
"id",
"forecast_date",
"temperature_min",
"temperature_max",
"temperature_mean",
"precipitation",
"precipitation_probability",
"humidity_mean",
"wind_speed_max",
"et0",
"weather_code",
]
class FarmSoilPayloadSerializer(serializers.Serializer):
resolved_metrics = serializers.JSONField()
metric_sources = serializers.JSONField()
depths = SoilDepthDataSerializer(many=True)
class FarmDetailSerializer(serializers.Serializer):
center_location = FarmCenterLocationSerializer()
weather = WeatherForecastDetailSerializer(allow_null=True)
sensor_payload = serializers.JSONField()
soil = FarmSoilPayloadSerializer()
plant_ids = serializers.ListField(child=serializers.IntegerField())
plants = PlantSerializer(many=True)
2026-04-24 02:50:27 +03:30
irrigation_method_id = serializers.IntegerField(allow_null=True)
irrigation_method = IrrigationMethodSerializer(allow_null=True)
2026-04-06 23:50:24 +03:30
created_at = serializers.DateTimeField()
updated_at = serializers.DateTimeField()