UPDATE
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
from location_data.serializers import SoilDepthDataSerializer
|
||||
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="لیست شناسه گیاهان مرتبط",
|
||||
)
|
||||
|
||||
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",
|
||||
}
|
||||
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
|
||||
|
||||
def validate(self, attrs):
|
||||
if "sensor_payload" not in attrs and "plant_ids" not in attrs:
|
||||
raise serializers.ValidationError(
|
||||
"حداقل یکی از sensor_payload یا plant_ids باید ارسال شود."
|
||||
)
|
||||
return attrs
|
||||
|
||||
|
||||
class SensorDataResponseSerializer(serializers.ModelSerializer):
|
||||
"""سریالایزر خروجی برای SensorData."""
|
||||
|
||||
plant_ids = serializers.PrimaryKeyRelatedField(
|
||||
source="plants",
|
||||
many=True,
|
||||
read_only=True,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = SensorData
|
||||
fields = [
|
||||
"farm_uuid",
|
||||
"center_location_id",
|
||||
"weather_forecast_id",
|
||||
"sensor_payload",
|
||||
"plant_ids",
|
||||
"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):
|
||||
farm_uuid = serializers.UUIDField()
|
||||
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)
|
||||
created_at = serializers.DateTimeField()
|
||||
updated_at = serializers.DateTimeField()
|
||||
Reference in New Issue
Block a user