From 9f96f353c666f629b6fc0eb8a8c9e40a803f333f Mon Sep 17 00:00:00 2001 From: Michael Bunsen Date: Fri, 3 Apr 2026 23:13:44 -0700 Subject: [PATCH 1/3] fix: remove stale project field from ProcessingServiceSerializer (#1209) The serializer had a write-only `project` PrimaryKeyRelatedField that was passed through to ProcessingService.objects.create(), but ProcessingService uses a M2M `projects` field, not a FK. This caused a TypeError on create. The field was left behind when #1094 moved project assignment to perform_create (which uses get_active_project from the query string). Remove the field entirely to match the TaxaList pattern: no writable project field on the serializer, M2M handled in perform_create. Also rename `project` to `project_id` in the frontend's generic convertToServerFieldValues to follow the codebase naming convention (ID values use _id suffix). Closes #1209 Co-Authored-By: Claude --- ami/ml/serializers.py | 7 ------- ami/ml/views.py | 1 + ui/src/data-services/hooks/entities/utils.ts | 2 +- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/ami/ml/serializers.py b/ami/ml/serializers.py index db91b31b1..e7e9e6aaf 100644 --- a/ami/ml/serializers.py +++ b/ami/ml/serializers.py @@ -2,7 +2,6 @@ from rest_framework import serializers from ami.main.api.serializers import DefaultSerializer, MinimalNestedModelSerializer -from ami.main.models import Project from .models.algorithm import Algorithm, AlgorithmCategoryMap from .models.pipeline import Pipeline, PipelineStage @@ -140,11 +139,6 @@ class ProcessingServiceSerializer(DefaultSerializer): projects = serializers.SerializerMethodField() is_async = serializers.BooleanField(read_only=True) endpoint_url = serializers.CharField(required=False, allow_null=True, allow_blank=False, max_length=1024) - project = serializers.PrimaryKeyRelatedField( - write_only=True, - queryset=Project.objects.all(), - required=False, - ) class Meta: model = ProcessingService @@ -161,7 +155,6 @@ class Meta: "updated_at", "last_seen", "last_seen_live", - "project", ] def get_projects(self, obj): diff --git a/ami/ml/views.py b/ami/ml/views.py index 58832a10b..2d1b573d9 100644 --- a/ami/ml/views.py +++ b/ami/ml/views.py @@ -166,6 +166,7 @@ def list(self, request, *args, **kwargs): def create(self, request, *args, **kwargs): data = request.data.copy() + data.pop("project", None) # Legacy field name; use project_id query param data["slug"] = slugify(data["name"]) serializer = self.get_serializer(data=data) serializer.is_valid(raise_exception=True) diff --git a/ui/src/data-services/hooks/entities/utils.ts b/ui/src/data-services/hooks/entities/utils.ts index a4723d4be..112b0a657 100644 --- a/ui/src/data-services/hooks/entities/utils.ts +++ b/ui/src/data-services/hooks/entities/utils.ts @@ -6,7 +6,7 @@ export const convertToServerFieldValues = (fieldValues: EntityFieldValues) => { return { ...(description ? { description } : {}), ...(name ? { name } : {}), - project: projectId, + project_id: projectId, ...(customFields ?? {}), } } From 3056bdba101b371efad00fbad4d0c72dfbb1bd80 Mon Sep 17 00:00:00 2001 From: Michael Bunsen Date: Fri, 3 Apr 2026 23:15:08 -0700 Subject: [PATCH 2/3] fix: remove unnecessary project pop from ProcessingService create view DRF ignores unknown fields in request body, so no need to strip `project` before passing to the serializer. Co-Authored-By: Claude --- ami/ml/views.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ami/ml/views.py b/ami/ml/views.py index 2d1b573d9..58832a10b 100644 --- a/ami/ml/views.py +++ b/ami/ml/views.py @@ -166,7 +166,6 @@ def list(self, request, *args, **kwargs): def create(self, request, *args, **kwargs): data = request.data.copy() - data.pop("project", None) # Legacy field name; use project_id query param data["slug"] = slugify(data["name"]) serializer = self.get_serializer(data=data) serializer.is_valid(raise_exception=True) From bad0c657ee6ac6cf72c4ccd8ef6ed4eadbf496d4 Mon Sep 17 00:00:00 2001 From: Michael Bunsen Date: Fri, 3 Apr 2026 23:26:42 -0700 Subject: [PATCH 3/3] fix: revert project_id rename in convertToServerFieldValues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Site, Device, and StorageSource serializers still expect `project` (not `project_id`) as a writable PrimaryKeyRelatedField in the request body. The ProcessingService fix is backend-only — the serializer no longer declares a `project` field, so DRF silently ignores it. Co-Authored-By: Claude --- ui/src/data-services/hooks/entities/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/data-services/hooks/entities/utils.ts b/ui/src/data-services/hooks/entities/utils.ts index 112b0a657..a4723d4be 100644 --- a/ui/src/data-services/hooks/entities/utils.ts +++ b/ui/src/data-services/hooks/entities/utils.ts @@ -6,7 +6,7 @@ export const convertToServerFieldValues = (fieldValues: EntityFieldValues) => { return { ...(description ? { description } : {}), ...(name ? { name } : {}), - project_id: projectId, + project: projectId, ...(customFields ?? {}), } }