First commit of claude's rework in django + vanillajs fronted
This commit is contained in:
93
apps/photos/serializers.py
Normal file
93
apps/photos/serializers.py
Normal file
@@ -0,0 +1,93 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
# Cross-app import (photos → tools). String FK in the model avoids DB circular
|
||||
# import; here we need the class directly for the serializer queryset.
|
||||
from apps.tools.models import ShotGroup
|
||||
|
||||
from .models import GroupPhoto, GroupPhotoAnalysis, Photo, PointOfImpact
|
||||
|
||||
|
||||
class PhotoMetaSerializer(serializers.ModelSerializer):
|
||||
"""Photo metadata only — the binary `data` field is never exposed in JSON."""
|
||||
|
||||
class Meta:
|
||||
model = Photo
|
||||
fields = ['id', 'content_type', 'size', 'width', 'height',
|
||||
'uploaded_by', 'uploaded_at', 'description']
|
||||
read_only_fields = ['id', 'size', 'width', 'height', 'uploaded_by', 'uploaded_at']
|
||||
|
||||
|
||||
class GroupPhotoAnalysisSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = GroupPhotoAnalysis
|
||||
fields = [
|
||||
'group_size_mm', 'group_size_moa',
|
||||
'elevation_offset_mm', 'elevation_offset_moa',
|
||||
'windage_offset_mm', 'windage_offset_moa',
|
||||
'mean_radius_mm', 'mean_radius_moa',
|
||||
'notes',
|
||||
]
|
||||
|
||||
def validate(self, attrs):
|
||||
instance = GroupPhotoAnalysis(**attrs)
|
||||
instance.clean()
|
||||
return attrs
|
||||
|
||||
|
||||
class PointOfImpactSerializer(serializers.ModelSerializer):
|
||||
# Write: accept Shot PK; Read: compact inline summary
|
||||
shot_detail = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = PointOfImpact
|
||||
fields = [
|
||||
'id', 'order',
|
||||
'shot', 'shot_detail',
|
||||
'x_px', 'y_px',
|
||||
'x_mm', 'y_mm', 'radius_mm',
|
||||
'notes',
|
||||
]
|
||||
|
||||
def get_shot_detail(self, obj):
|
||||
if not obj.shot_id:
|
||||
return None
|
||||
return {
|
||||
'id': obj.shot.pk,
|
||||
'shot_number': obj.shot.shot_number,
|
||||
'velocity_fps': str(obj.shot.velocity_fps),
|
||||
}
|
||||
|
||||
|
||||
class GroupPhotoSerializer(serializers.ModelSerializer):
|
||||
photo = PhotoMetaSerializer(read_only=True)
|
||||
photo_id = serializers.PrimaryKeyRelatedField(
|
||||
source='photo',
|
||||
queryset=Photo.objects.all(),
|
||||
write_only=True,
|
||||
)
|
||||
# shot_group is optional — photos can exist independently of any group
|
||||
shot_group = serializers.PrimaryKeyRelatedField(
|
||||
queryset=ShotGroup.objects.all(),
|
||||
required=False, allow_null=True,
|
||||
)
|
||||
shot_group_detail = serializers.SerializerMethodField()
|
||||
analysis = GroupPhotoAnalysisSerializer(read_only=True)
|
||||
points_of_impact = PointOfImpactSerializer(many=True, read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = GroupPhoto
|
||||
fields = [
|
||||
'id', 'photo_id', 'photo',
|
||||
'shot_group', 'shot_group_detail', 'caption', 'order',
|
||||
'is_public', 'analysis', 'points_of_impact',
|
||||
]
|
||||
|
||||
def get_shot_group_detail(self, obj):
|
||||
if not obj.shot_group_id:
|
||||
return None
|
||||
sg = obj.shot_group
|
||||
return {
|
||||
'id': sg.pk,
|
||||
'label': sg.label,
|
||||
'distance_m': str(sg.distance_m) if sg.distance_m else None,
|
||||
}
|
||||
Reference in New Issue
Block a user