1
0
Fork 0
mirror of https://github.com/seanmorley15/AdventureLog.git synced 2025-07-24 15:29:36 +02:00

refactor(serializers): rename Adventure to Location and update related fields

This commit is contained in:
Sean Morley 2025-07-09 23:08:54 -04:00
parent c5639bed75
commit 0566c71caa

View file

@ -1,6 +1,6 @@
from django.utils import timezone
import os
from .models import Adventure, AdventureImage, ChecklistItem, Collection, Note, Transportation, Checklist, Visit, Category, Attachment, Lodging
from .models import Location, LocationImage, ChecklistItem, Collection, Note, Transportation, Checklist, Visit, Category, Attachment, Lodging
from rest_framework import serializers
from main.utils import CustomModelSerializer
from users.serializers import CustomUserDetailsSerializer
@ -9,17 +9,17 @@ from geopy.distance import geodesic
from integrations.models import ImmichIntegration
class AdventureImageSerializer(CustomModelSerializer):
class LocationImageSerializer(CustomModelSerializer):
class Meta:
model = AdventureImage
fields = ['id', 'image', 'adventure', 'is_primary', 'user_id', 'immich_id']
read_only_fields = ['id', 'user_id']
model = LocationImage
fields = ['id', 'image', 'location', 'is_primary', 'user', 'immich_id']
read_only_fields = ['id', 'user']
def to_representation(self, instance):
# If immich_id is set, check for user integration once
integration = None
if instance.immich_id:
integration = ImmichIntegration.objects.filter(user=instance.user_id).first()
integration = ImmichIntegration.objects.filter(user=instance.user).first()
if not integration:
return None # Skip if Immich image but no integration
@ -42,8 +42,8 @@ class AttachmentSerializer(CustomModelSerializer):
extension = serializers.SerializerMethodField()
class Meta:
model = Attachment
fields = ['id', 'file', 'adventure', 'extension', 'name', 'user_id']
read_only_fields = ['id', 'user_id']
fields = ['id', 'file', 'location', 'extension', 'name', 'user']
read_only_fields = ['id', 'user']
def get_extension(self, obj):
return obj.file.name.split('.')[-1]
@ -59,11 +59,11 @@ class AttachmentSerializer(CustomModelSerializer):
return representation
class CategorySerializer(serializers.ModelSerializer):
num_adventures = serializers.SerializerMethodField()
num_locations = serializers.SerializerMethodField()
class Meta:
model = Category
fields = ['id', 'name', 'display_name', 'icon', 'num_adventures']
read_only_fields = ['id', 'num_adventures']
fields = ['id', 'name', 'display_name', 'icon', 'num_locations']
read_only_fields = ['id', 'num_locations']
def validate_name(self, value):
return value.lower()
@ -71,7 +71,7 @@ class CategorySerializer(serializers.ModelSerializer):
def create(self, validated_data):
user = self.context['request'].user
validated_data['name'] = validated_data['name'].lower()
return Category.objects.create(user_id=user, **validated_data)
return Category.objects.create(user=user, **validated_data)
def update(self, instance, validated_data):
for attr, value in validated_data.items():
@ -81,8 +81,8 @@ class CategorySerializer(serializers.ModelSerializer):
instance.save()
return instance
def get_num_adventures(self, obj):
return Adventure.objects.filter(category=obj, user_id=obj.user_id).count()
def get_num_locations(self, obj):
return Location.objects.filter(category=obj, user=obj.user).count()
class VisitSerializer(serializers.ModelSerializer):
@ -91,13 +91,12 @@ class VisitSerializer(serializers.ModelSerializer):
fields = ['id', 'start_date', 'end_date', 'timezone', 'notes']
read_only_fields = ['id']
class AdventureSerializer(CustomModelSerializer):
class LocationSerializer(CustomModelSerializer):
images = serializers.SerializerMethodField()
visits = VisitSerializer(many=True, read_only=False, required=False)
attachments = AttachmentSerializer(many=True, read_only=True)
category = CategorySerializer(read_only=False, required=False)
is_visited = serializers.SerializerMethodField()
user = serializers.SerializerMethodField()
country = CountrySerializer(read_only=True)
region = RegionSerializer(read_only=True)
city = CitySerializer(read_only=True)
@ -108,16 +107,22 @@ class AdventureSerializer(CustomModelSerializer):
)
class Meta:
model = Adventure
model = Location
fields = [
'id', 'user_id', 'name', 'description', 'rating', 'activity_types', 'location',
'id', 'name', 'description', 'rating', 'tags', 'location',
'is_public', 'collections', 'created_at', 'updated_at', 'images', 'link', 'longitude',
'latitude', 'visits', 'is_visited', 'category', 'attachments', 'user', 'city', 'country', 'region'
]
read_only_fields = ['id', 'created_at', 'updated_at', 'user_id', 'is_visited', 'user']
read_only_fields = ['id', 'created_at', 'updated_at', 'user', 'is_visited']
# Makes it so the whole user object is returned in the serializer instead of just the user uuid
def to_representation(self, instance):
representation = super().to_representation(instance)
representation['user'] = CustomUserDetailsSerializer(instance.user, context=self.context).data
return representation
def get_images(self, obj):
serializer = AdventureImageSerializer(obj.images.all(), many=True, context=self.context)
serializer = LocationImageSerializer(obj.images.all(), many=True, context=self.context)
# Filter out None values from the serialized data
return [image for image in serializer.data if image is not None]
@ -128,7 +133,7 @@ class AdventureSerializer(CustomModelSerializer):
user = self.context['request'].user
for collection in collections:
if collection.user_id != user and not collection.shared_with.filter(id=user.id).exists():
if collection.user != user and not collection.shared_with.filter(id=user.id).exists():
raise serializers.ValidationError(
f"Collection '{collection.name}' does not belong to the current user."
)
@ -140,7 +145,7 @@ class AdventureSerializer(CustomModelSerializer):
if category_data:
user = self.context['request'].user
name = category_data.get('name', '').lower()
existing_category = Category.objects.filter(user_id=user, name=name).first()
existing_category = Category.objects.filter(user=user, name=name).first()
if existing_category:
return existing_category
category_data['name'] = name
@ -162,7 +167,7 @@ class AdventureSerializer(CustomModelSerializer):
icon = category_data.icon
category, created = Category.objects.get_or_create(
user_id=user,
user=user,
name=name,
defaults={
'display_name': display_name,
@ -171,10 +176,6 @@ class AdventureSerializer(CustomModelSerializer):
)
return category
def get_user(self, obj):
user = obj.user_id
return CustomUserDetailsSerializer(user).data
def get_is_visited(self, obj):
return obj.is_visited_status()
@ -184,24 +185,24 @@ class AdventureSerializer(CustomModelSerializer):
collections_data = validated_data.pop('collections', [])
print(category_data)
adventure = Adventure.objects.create(**validated_data)
location = Location.objects.create(**validated_data)
# Handle visits
for visit_data in visits_data:
Visit.objects.create(adventure=adventure, **visit_data)
Visit.objects.create(location=location, **visit_data)
# Handle category
if category_data:
category = self.get_or_create_category(category_data)
adventure.category = category
location.category = category
# Handle collections - set after adventure is saved
# Handle collections - set after location is saved
if collections_data:
adventure.collections.set(collections_data)
location.collections.set(collections_data)
adventure.save()
location.save()
return adventure
return location
def update(self, instance, validated_data):
has_visits = 'visits' in validated_data
@ -214,9 +215,9 @@ class AdventureSerializer(CustomModelSerializer):
for attr, value in validated_data.items():
setattr(instance, attr, value)
# Handle category - ONLY allow the adventure owner to change categories
# Handle category - ONLY allow the location owner to change categories
user = self.context['request'].user
if category_data and instance.user_id == user:
if category_data and instance.user == user:
# Only the owner can set categories
category = self.get_or_create_category(category_data)
instance.category = category
@ -241,13 +242,13 @@ class AdventureSerializer(CustomModelSerializer):
visit.save()
updated_visit_ids.add(visit_id)
else:
new_visit = Visit.objects.create(adventure=instance, **visit_data)
new_visit = Visit.objects.create(location=instance, **visit_data)
updated_visit_ids.add(new_visit.id)
visits_to_delete = current_visit_ids - updated_visit_ids
instance.visits.filter(id__in=visits_to_delete).delete()
# call save on the adventure to update the updated_at field and trigger any geocoding
# call save on the location to update the updated_at field and trigger any geocoding
instance.save()
return instance
@ -258,13 +259,13 @@ class TransportationSerializer(CustomModelSerializer):
class Meta:
model = Transportation
fields = [
'id', 'user_id', 'type', 'name', 'description', 'rating',
'id', 'user', 'type', 'name', 'description', 'rating',
'link', 'date', 'flight_number', 'from_location', 'to_location',
'is_public', 'collection', 'created_at', 'updated_at', 'end_date',
'origin_latitude', 'origin_longitude', 'destination_latitude', 'destination_longitude',
'start_timezone', 'end_timezone', 'distance' # ✅ Add distance here
'start_timezone', 'end_timezone', 'distance'
]
read_only_fields = ['id', 'created_at', 'updated_at', 'user_id', 'distance']
read_only_fields = ['id', 'created_at', 'updated_at', 'user', 'distance']
def get_distance(self, obj):
if (
@ -284,29 +285,29 @@ class LodgingSerializer(CustomModelSerializer):
class Meta:
model = Lodging
fields = [
'id', 'user_id', 'name', 'description', 'rating', 'link', 'check_in', 'check_out',
'id', 'user', 'name', 'description', 'rating', 'link', 'check_in', 'check_out',
'reservation_number', 'price', 'latitude', 'longitude', 'location', 'is_public',
'collection', 'created_at', 'updated_at', 'type', 'timezone'
]
read_only_fields = ['id', 'created_at', 'updated_at', 'user_id']
read_only_fields = ['id', 'created_at', 'updated_at', 'user']
class NoteSerializer(CustomModelSerializer):
class Meta:
model = Note
fields = [
'id', 'user_id', 'name', 'content', 'date', 'links',
'id', 'user', 'name', 'content', 'date', 'links',
'is_public', 'collection', 'created_at', 'updated_at'
]
read_only_fields = ['id', 'created_at', 'updated_at', 'user_id']
read_only_fields = ['id', 'created_at', 'updated_at', 'user']
class ChecklistItemSerializer(CustomModelSerializer):
class Meta:
model = ChecklistItem
fields = [
'id', 'user_id', 'name', 'is_checked', 'checklist', 'created_at', 'updated_at'
'id', 'user', 'name', 'is_checked', 'checklist', 'created_at', 'updated_at'
]
read_only_fields = ['id', 'created_at', 'updated_at', 'user_id', 'checklist']
read_only_fields = ['id', 'created_at', 'updated_at', 'user', 'checklist']
class ChecklistSerializer(CustomModelSerializer):
items = ChecklistItemSerializer(many=True, source='checklistitem_set')
@ -314,21 +315,21 @@ class ChecklistSerializer(CustomModelSerializer):
class Meta:
model = Checklist
fields = [
'id', 'user_id', 'name', 'date', 'is_public', 'collection', 'created_at', 'updated_at', 'items'
'id', 'user', 'name', 'date', 'is_public', 'collection', 'created_at', 'updated_at', 'items'
]
read_only_fields = ['id', 'created_at', 'updated_at', 'user_id']
read_only_fields = ['id', 'created_at', 'updated_at', 'user']
def create(self, validated_data):
items_data = validated_data.pop('checklistitem_set')
checklist = Checklist.objects.create(**validated_data)
for item_data in items_data:
# Remove user_id from item_data to avoid constraint issues
item_data.pop('user_id', None)
# Set user_id from the parent checklist
# Remove user from item_data to avoid constraint issues
item_data.pop('user', None)
# Set user from the parent checklist
ChecklistItem.objects.create(
checklist=checklist,
user_id=checklist.user_id,
user=checklist.user,
**item_data
)
return checklist
@ -348,8 +349,8 @@ class ChecklistSerializer(CustomModelSerializer):
# Update or create items
updated_item_ids = set()
for item_data in items_data:
# Remove user_id from item_data to avoid constraint issues
item_data.pop('user_id', None)
# Remove user from item_data to avoid constraint issues
item_data.pop('user', None)
item_id = item_data.get('id')
if item_id:
@ -363,14 +364,14 @@ class ChecklistSerializer(CustomModelSerializer):
# If ID is provided but doesn't exist, create new item
ChecklistItem.objects.create(
checklist=instance,
user_id=instance.user_id,
user=instance.user,
**item_data
)
else:
# If no ID is provided, create new item
ChecklistItem.objects.create(
checklist=instance,
user_id=instance.user_id,
user=instance.user,
**item_data
)
@ -391,7 +392,7 @@ class ChecklistSerializer(CustomModelSerializer):
return data
class CollectionSerializer(CustomModelSerializer):
adventures = AdventureSerializer(many=True, read_only=True)
locations = LocationSerializer(many=True, read_only=True)
transportations = TransportationSerializer(many=True, read_only=True, source='transportation_set')
notes = NoteSerializer(many=True, read_only=True, source='note_set')
checklists = ChecklistSerializer(many=True, read_only=True, source='checklist_set')
@ -399,8 +400,8 @@ class CollectionSerializer(CustomModelSerializer):
class Meta:
model = Collection
fields = ['id', 'description', 'user_id', 'name', 'is_public', 'adventures', 'created_at', 'start_date', 'end_date', 'transportations', 'notes', 'updated_at', 'checklists', 'is_archived', 'shared_with', 'link', 'lodging']
read_only_fields = ['id', 'created_at', 'updated_at', 'user_id']
fields = ['id', 'description', 'user', 'name', 'is_public', 'locations', 'created_at', 'start_date', 'end_date', 'transportations', 'notes', 'updated_at', 'checklists', 'is_archived', 'shared_with', 'link', 'lodging']
read_only_fields = ['id', 'created_at', 'updated_at', 'user']
def to_representation(self, instance):
representation = super().to_representation(instance)