Optimize Role and Membership bulk creation with bulk_create#14341
Optimize Role and Membership bulk creation with bulk_create#14341rtibblesbot wants to merge 1 commit intolearningequality:developfrom
Conversation
rtibbles
left a comment
There was a problem hiding this comment.
This is a good start, but I think we can make a cleaner approach.
Let's keep the focus on efficient bulk creates - so a small number of efficient queries for validation and creation.
|
Thanks for the review! I've addressed all the feedback:
|
|
Responses to review feedback:
|
Build Artifacts
Smoke test screenshot |
681e189 to
866a747
Compare
rtibbles
left a comment
There was a problem hiding this comment.
This is a significant improvement already, great work!
I realize this wasn't explicitly in the acceptance criteria, but we should be thinking about the overall performance here for the bulk create - it doesn't help to make the writes in bulk, if we're still doing hundreds of individual read queries (this is OK on SQLite, but it will be slow in postgres). So making sure we're not scaling queries as O(n) would be great to see in the tests.
866a747 to
b00bbab
Compare
|
Thanks for the thorough review! Here's a summary of changes:
|
|
Responses to review feedback:
Dropping either one loses something: without the pre-filter we can't tell what's new; without
Note: DRF's |
692ce4e to
72accb7
Compare
rtibbles
left a comment
There was a problem hiding this comment.
Still need to clean up inline imports.
72accb7 to
21c1ab5
Compare
|
Moved all inline imports to file-level. Thanks for catching these. |
|
Not sure why your moving of imports into the module scope warrants its own commit when you've been happy to rebase and force push. Please clean up. |
0836c80 to
9c12d92
Compare
9c12d92 to
20a239f
Compare
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
20a239f to
1e08df1
Compare
|
Squashed the import cleanup commit into the main commit. Now a single commit on the branch. |
Summary
Replaces individual
get_or_createloops inRoleListSerializerandMembershipListSerializerwith Django'sbulk_createfor significantly better performance when assigning coaches to multiple classes or enrolling multiple users.Morango
SyncableModelinstances need manual preparation beforebulk_createsincesave()is bypassed — a_prepare_for_bulk_createhelper callspre_save(),calculate_uuid(), and sets_morango_dirty_bit. Both serializers filter out already-existing records by their deterministic morango UUID before callingbulk_create, so the response accurately reflects only newly created objects.Classroom coach roles still use individual
get_or_createbecauseRole.save()has a side effect of creating anASSIGNABLE_COACHrole at facility level. All other roles (facility-level admin/coach) and all memberships use the optimized bulk path.Validation is preserved:
pre_save()→ensure_dataset()Test evidence
References
Closes #13657
Related: #13614 (original bulk coach assignment PR that identified this optimization)
Reviewer guidance
RoleListSerializer.create()for the branching logic._prepare_for_bulk_createaccesses morango internals (pre_save,calculate_uuid,_morango_dirty_bit) — there's no public morango API for bulk operations onSyncableModel. ThePrepareForBulkCreateTestCasetests verify these fields are set correctly and that UUIDs are deterministic._get_batch_sizefollows the same pattern askolibri.core.auth.utils.migrate._batch_saveto avoid SQLite variable limits.transaction.atomic()for consistency.AI usage
Claude Code implemented this feature following the approach outlined in the issue thread. The implementation was reviewed for code reuse (checked against existing
_batch_savepatterns), code quality (validation coverage, transaction consistency), and efficiency (batch_size protection, justified pre-filter query). Tests were written to cover all paths including morango field integrity, idempotency, and validation edge cases.@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly
How was this generated?
Closes #13657