Skip to content

Bulk destroy answers each key's outcome; destroy returns {pk: None} (0.15.0) - #81

Merged
velis74 merged 3 commits into
mainfrom
fix-destroy-result
Nov 12, 2026
Merged

velis74 merged 3 commits into
mainfrom
fix-destroy-result

Conversation

@velis74

@velis74 velis74 commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Change

  • bulk_destroy deletes each key independently of the others and answers 200 with one object keyed by pk: null for a deleted record, the failure's ApiErrorBody otherwise (fastapi-viewsets.not_found for a missing record). perform_bulk_destroy returns dict[K, ApiErrorBody | None].
  • ImplMixin.perform_bulk_destroy has a default over perform_destroy: an HTTPException or RequestValidationError becomes that key's ApiErrorBody, any other exception propagates, a repeated key is deleted once. CollectionViewSet and DjangoORMViewSet use it.
  • destroy / perform_destroy return dict[K, None]. DjangoORMViewSet.perform_destroy returned {"id": pk}, which failed response validation (500) for a non-string key and did not encode as the declared result in a celery_viewset worker (500 fastapi-viewsets.action_failed, reason: result).
  • ChangeEvents publishes only the deleted pks of a bulk destroy.
  • TS: DestroyReturnData<K> = Record<K, null>; bulkDestroy() returns BulkDestroyReturnData<K> = Record<K, ApiErrorBody | null>.

Breaking: 0.15.0 for both packages. The TODO entry on the non-atomic Django bulk destroy is removed.

Tests

  • Per-key results with a missing and a repeated key; a non-HTTP exception propagates (CollectionViewSet).
  • Django: bulk result with a missing key, the others deleted; both results encode through ActionCodec.
  • Events: a bulk destroy with a missing key answers 200 and publishes only the deleted pk.
  • TS proxy specs for the new answer shapes.

…ares

perform_destroy returned {"id": pk}, which does not validate as destroy's
dict[K, Any]: REST answered 500, and a celery_viewset worker failed the
call with action_failed (reason: result). 0.14.3.
@github-actions

github-actions Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

✅ Incremental coverage — 96.3%

███████████████████░ 26 / 27 changed lines covered · threshold 70% · main → fix-destroy-result

File Coverage Covered Uncovered lines
⚠️ fastapi_viewsets/events/changes.py 83.3% 5 / 6 256
✅ fastapi_viewsets/backends/django_orm.py 100% 2 / 2 —
✅ fastapi_viewsets/collection_viewset.py 100% 1 / 1 —
✅ fastapi_viewsets/mixins.py 100% 16 / 16 —
✅ vue/mixins.ts 100% 0 / 0 no executable lines changed
✅ vue/proxy-base.ts 100% 2 / 2 —
Total 96.3% 26 / 27
19 files not graded (6 ignored by pattern, 1 no added lines, 12 not source files)
File Reason
TODO.md no added lines
changelog.md not a source file
docs/api/events.md not a source file
docs/api/python-mixins.md not a source file
docs/api/vue-mixins.md not a source file
docs/guide/events.md not a source file
docs/guide/migration.md not a source file
docs/guide/python-mixins.md not a source file
docs/guide/route-rest.md not a source file
fastapi_viewsets/backends/django_orm_test.py ignored by *_test.py
fastapi_viewsets/collection_viewset_test.py ignored by *_test.py
fastapi_viewsets/events/changes_test.py ignored by *_test.py
fastapi_viewsets/mixins_test.py ignored by *_test.py
package-lock.json not a source file
package.json not a source file
pyproject.toml not a source file
uv.lock not a source file
vue/index.ts ignored by vue/index.ts
vue/rest-proxy.spec.ts ignored by *.spec.*

Coverage reports: coverage.json (coverage.py, 69 files) · coverage/clover.xml (clover, 13 files) — incremental-coverage-check v3.0.0

bulk_destroy deletes every key independently and answers 200 with one object
keyed by pk: null for a deleted record, the failure's ApiErrorBody otherwise.
ImplMixin.perform_bulk_destroy implements it over perform_destroy; the
CollectionViewSet and DjangoORMViewSet overrides are removed. destroy returns
{pk: None}. ChangeEvents publishes only the deleted pks of a bulk destroy.
TS: DestroyReturnData<K>, BulkDestroyReturnData<K>.
@velis74 velis74 changed the title DjangoORMViewSet: destroy returns {pk: None}, the result destroy declares (0.14.3) Bulk destroy answers each key's outcome; destroy returns {pk: None} (0.15.0) Nov 12, 2026
@velis74
velis74 merged commit 7b921ec into main Nov 12, 2026
6 checks passed
@velis74
velis74 deleted the fix-destroy-result branch November 12, 2026 09:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant