|
18 | 18 | import six |
19 | 19 | from django.apps import apps |
20 | 20 | from django.contrib.auth.models import User |
21 | | -from django.db import models |
| 21 | +from django.db import models, IntegrityError, transaction |
22 | 22 | from django.utils.encoding import python_2_unicode_compatible |
23 | 23 | from django.utils.timezone import now |
24 | 24 | from lazy import lazy |
@@ -212,16 +212,45 @@ def bulk_create(cls, user_id, course_key, block_record_lists): |
212 | 212 | for the block records' course with the new VisibleBlocks. |
213 | 213 | Returns the newly created visible blocks. |
214 | 214 | """ |
215 | | - created = cls.objects.bulk_create([ |
| 215 | + visual_blocks = [ |
216 | 216 | VisibleBlocks( |
217 | 217 | blocks_json=brl.json_value, |
218 | 218 | hashed=brl.hash_value, |
219 | 219 | course_id=course_key, |
220 | 220 | ) |
221 | 221 | for brl in block_record_lists |
222 | | - ]) |
223 | | - cls._update_cache(user_id, course_key, created) |
224 | | - return created |
| 222 | + ] |
| 223 | + |
| 224 | + created_visual_blocks = [] |
| 225 | + existing_visual_blocks = [] |
| 226 | + |
| 227 | + try: |
| 228 | + # Try to bulk create the blocks assuming all blocks are new |
| 229 | + with transaction.atomic(): |
| 230 | + created_visual_blocks = cls.objects.bulk_create(visual_blocks) |
| 231 | + except IntegrityError: |
| 232 | + log.warning('Falling back to create VisualBlocks one by one for user {} in course {}'.format( |
| 233 | + user_id, |
| 234 | + course_key |
| 235 | + )) |
| 236 | + |
| 237 | + # Try to create blocks one by one and mark newly created blocks |
| 238 | + for visual_block in visual_blocks: |
| 239 | + existing_blocks = cls.objects.filter(hashed=visual_block.hashed) |
| 240 | + |
| 241 | + if existing_blocks.exists(): |
| 242 | + # As only one record has a matching hash it is safe to use first |
| 243 | + existing_visual_blocks.append(existing_blocks.first()) |
| 244 | + else: |
| 245 | + # Create the visual block and add mark as newly created |
| 246 | + visual_block.save() |
| 247 | + created_visual_blocks.append(visual_block) |
| 248 | + |
| 249 | + # Update the cache with the conjunction of created and existing blocks |
| 250 | + cls._update_cache(user_id, course_key, existing_visual_blocks + created_visual_blocks) |
| 251 | + |
| 252 | + # Return the new visual blocks |
| 253 | + return created_visual_blocks |
225 | 254 |
|
226 | 255 | @classmethod |
227 | 256 | def bulk_get_or_create(cls, user_id, course_key, block_record_lists): |
|
0 commit comments