Skip to content

Fix: Update attachments in BE instead of cloning record - #8400

Open
CarolineDenis wants to merge 5 commits into
mainfrom
issue-8298
Open

Fix: Update attachments in BE instead of cloning record#8400
CarolineDenis wants to merge 5 commits into
mainfrom
issue-8298

Conversation

@CarolineDenis

@CarolineDenis CarolineDenis commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Fixes #8298

Changes

  • Added explicit identity-preservation support through the upload pipeline.
  • Added schema support so plans containing preserveIdentity validate.

Checklist

  • Self-review the PR after opening it to make sure the changes look good and
    self-explanatory (or properly documented)
  • Add relevant issue to release milestone
  • Add pr to documentation list
  • Add automated tests
  • Add a reverse migration if a migration is present in the PR
  • Add migration function to
    def fix_schema_config(stdout: WriteToStdOut | None = None):

Testing instructions

  • Follow issue description and verify original attachment is being modified rather than having a new one being created

Notes:
Attachments were cloned because:

In upload_table.py:986:

  1. In update mode, non-one-to-one related records go through process_row unless preserveIdentity is set.
  • See BoundUpdateTable._process_to_ones.
  • Without preserveIdentity, attachment went down the process_row path, not save_row(force=True).
  1. process_row does match-first, then upload if no match.
  • See BoundUploadTable._handle_row and BoundUploadTable._match.
  • In that upload path, if current_id exists, upload means clone, not update.
  1. See BoundUploadTable._do_upload and BoundUploadTable._do_clone.

So when we changed attachment fields, the old record often no longer matched the match predicate, and the fallback was “create via clone” from current_id, which produced duplicate attachments.

For many non-one-to-one relationships, Specify treats records as potentially reusable/shared and avoids unconditional in-place mutation, that conservative default is useful broadly.

==> preserveIdentity flips that specific to-one node from match/clone semantics to forced in-place save when there is an existing id

Next

A better long-term model is an explicit per-node update strategy in the upload plan.
Each table instance in the relationship graph explicitly declares how updates should behave, instead of relying on one global default.

Summary by CodeRabbit

  • Bug Fixes

    • Fixed batch edits for existing attachment records, preserving their identities and relationships.
    • Attachment updates now keep record counts stable and maintain audit history.
    • Improved one-to-one upload handling to update existing records when configured.
  • New Features

    • Upload plans now support optional identity preservation settings for upload tables and related records.

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

Warning

One or more dependencies are approaching or past End-of-Life.
Please plan upgrades accordingly.

STATUS=WARNING
NODE_VERSION=20
NODE_CYCLE=20
EOL_DATE=2026-04-30
DAYS_REMAINING=-97

--- Node.js ---
Version: 20
EOL: 2026-04-30
Status: WARNING

STATUS=OK
PYTHON_VERSION=3.12
PYTHON_CYCLE=3.12
EOL_DATE=2028-10-31
DAYS_REMAINING=818

--- Python ---
Version: 3.12
EOL: 2028-10-31
Status: OK

STATUS=WARNING
DJANGO_VERSION=4.2
DJANGO_CYCLE=4.2
EOL_DATE=2026-04-07
DAYS_REMAINING=-120

--- Django ---
Version: 4.2
EOL: 2026-04-07
Status: WARNING


@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Attachment identity preservation

Layer / File(s) Summary
Upload identity contract
specifyweb/backend/workbench/upload/upload_plan_schema.py, specifyweb/backend/workbench/upload/upload_table.py, specifyweb/backend/workbench/upload/scoping.py
Upload plans accept preserveIdentity. The flag propagates through parsing, serialization, scoping, and binding.
Attachment in-place updates
specifyweb/backend/stored_queries/batch_edit.py, specifyweb/backend/workbench/upload/upload_table.py
Attachment tables enable identity preservation. Existing one-to-one records use in-place updates when the flag and current integer identity are present.
Attachment batch-edit validation
specifyweb/backend/workbench/upload/tests/test_batch_edit_table.py
Tests cover attachment updates through collection-object queries, direct attachment queries, and dataset commits. They verify retained identities, relationships, counts, titles, and audit entries.

Possibly related PRs

Suggested reviewers: alesan99, g1rly-c0d3r

🚥 Pre-merge checks | ✅ 5 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Testing Instructions ⚠️ Warning The Testing instructions section contains only template comments, but the change affects upload planning, schema parsing, and three attachment batch-edit flows. Add runnable test commands and steps for relationship and direct Attachment edits, dataset commit, preserveIdentity validation, ID/count/link preservation, and audit logging.
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR implements the required fix for issue #8298 by adding preserveIdentity support to prevent attachment record duplication and preserve Edit History.
Out of Scope Changes check ✅ Passed All changes directly support the core objective of enabling identity preservation for attachment updates; no unrelated modifications are present.
Automatic Tests ✅ Passed PR includes comprehensive automatic tests: three new test methods in test_batch_edit_table.py covering attachment updates through collection-object relationship, direct attachment table queries,...
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: updating attachments in place through the backend instead of cloning records.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-8298

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@CarolineDenis

Copy link
Copy Markdown
Contributor Author

@CodeRabbit full review

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@CarolineDenis
CarolineDenis requested a review from a team August 25, 2026 18:20

@g1rly-c0d3r g1rly-c0d3r left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Follow issue description and verify original attachment is being modified rather than having a new one being created

No duplicate attachment records, and I was able to see all of the edit history.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: 📋Back Log

Development

Successfully merging this pull request may close these issues.

Batch editing an attachment record does not edit the record and instead duplicates it

2 participants