def handle_related_models(object_list, parent, clean, **kwargs): """ Create/find and attach all related models for a piece. :param object_list: The list of objects to create/find, and which field they belong to, in the format [{id: field_name, value: x},] :param parent: The object to relate to. :param clean: A Cleanup object. :kwargs creator: the creator of the piece, taken from request.user birth_date: The birth-date of a composer object death_date: The death-date of a composer object """ for item in object_list: field = item.get("id") if field == "title": parent.title = item.get("value") continue if field == "composer": birth_date = kwargs.pop("birth_date", None) death_date = kwargs.pop("death_date", None) try: composer_list = abstract_model_factory( item.get("value"), "Composer", clean, birth_date=birth_date, death_date=death_date ) composer = composer_list[0] parent.composer = composer continue except: clean.cleanup() raise if field == "collections": user = kwargs.pop("user", None) try: collection_list = abstract_model_factory(item.get("value"), "Collection", clean, creator=user) for x in collection_list: x.add(parent) continue except: clean.cleanup() raise if field == "languages": try: language_list = abstract_model_factory(item.get("value"), "Language", clean) parent.languages.clear() for x in language_list: parent.languages.add(x) continue except: clean.cleanup() raise if field == "locations": try: location_list = abstract_model_factory(item.get("value"), "Location", clean) parent.locations.clear() for x in location_list: parent.locations.add(x) continue except: clean.cleanup() raise if field == "sources": try: source_list = abstract_model_factory(item.get("value"), "Source", clean) parent.sources.clear() for x in source_list: parent.sources.add(x) continue except: clean.cleanup() raise if field == "tags": try: tag_list = abstract_model_factory(item.get("value"), "Tag", clean) parent.tags.clear() for x in tag_list: parent.tags.add(x) continue except: clean.cleanup() raise if field == "genres": try: genre_list = abstract_model_factory(item.get("value"), "Genre", clean) parent.genres.clear() for x in genre_list: parent.genres.add(x) continue except: clean.cleanup() raise if field == "instruments_voices": try: ins_list = abstract_model_factory(item.get("value"), "InstrumentVoice", clean) parent.instruments_voices.clear() for x in ins_list: parent.instruments_voices.add(x) continue except: clean.cleanup() raise if field == "number_of_voices": parent.number_of_voices = int(item.get("value")) if field == "vocalization": parent.vocalization = item.get("value") if field == "religiosity": parent.religiosity = item.get("value") if field == "composition_start_date" and item.get("value"): parent.composition_start_date = int(item.get("value")) if field == "composition_end_date" and item.get("value"): parent.composition_end_date = int(item.get("value")) if field == "comment": parent.comment = item.get("value")
def piece_update(request, *args, **kwargs): # Update a piece based on a dict of changes in request.POST['changes'] patch_data = request.data form = validate_dynamic_piece_form(request, PieceForm(patch_data)) if not form.is_valid(): # Form errors are rendered for user on the front end. Collection # validation errors are ignored, as these cannot be modified from # the update page. if form.errors.get("collections"): del form.errors["collections"] if form.errors: errors = {f: [e.get_json_data()[0]["message"]] for f, e in form.errors.items()} errors = json.dumps({"errors": errors}) return HttpResponse(content=errors, content_type="application/json", status=status.HTTP_400_BAD_REQUEST) clean = Cleanup() piece = Piece.objects.get(id=int(kwargs["pk"])) change = json.loads(patch_data["changes"]) """ Creating new movements must occur before old movements are deleted, as the attachment of files depends on the ordering and numbering of movements in the piece's present state. See comment in handle_dynamic_file_table() for more information. """ handle_dynamic_file_table(request, piece, clean) modify_movements = [x for x in change["modify"] if x["type"] == "M"] if modify_movements: for item in modify_movements: mov = Movement.objects.filter(id=item["id"]) if not mov: break mov = mov[0] if item.get("tags"): tag_list = abstract_model_factory(item["tags"], "Tag", clean) mov.tags.clear() for x in tag_list: mov.tags.add(x) if item.get("instruments_voices"): ins_list = abstract_model_factory(item["instruments_voices"], "InstrumentVoice", clean) mov.instruments_voices.clear() for x in ins_list: mov.instruments_voices.add(x) if item.get("comment"): mov.comment = item["comment"] if item.get("number_of_voices"): mov.number_of_voices = int(item["number_of_voices"]) if item.get("vocalization"): mov.vocalization = item["vocalization"] if item.get("title"): mov.title = item["title"] mov.save() movement_positions = [x for x in change["modify"] if x["type"] == "M" and x.get("position")] movement_positions.extend([x for x in change["add"] if x["type"] == "M" and x.get("position")]) if movement_positions: movements = piece.movements.all() for item in movement_positions: if item.get("id"): mov = movements.get(id=item["id"]) mov.position = item["position"] mov.save() elif item.get("name"): mov = movements.get(title=item["name"]) mov.position = item["position"] mov.save() modify_atts = [x for x in change["modify"] if x["type"] == "A"] if modify_atts: for item in modify_atts: att = Attachment.objects.filter(pk=item["id"]) if not att: break att = att[0] if item.get("parent"): if item.get("newParentTitle") == "Attach to Piece": att.movements.clear() att.pieces.clear() att.pieces.add(piece) att.save() else: mov = piece.movements.filter(title=item["newParentTitle"]) if not mov: break mov = mov[0] att.movements.clear() att.pieces.clear() att.movements.add(mov) att.save() if item.get("source"): att.source = item.get("source") att.save() modify_piece = [x for x in change["modify"] if x["type"] == "F"] if modify_piece: # Can use the same function as the piece-create here. handle_related_models(modify_piece, piece, clean) delete_attachments = [x for x in change["delete"] if x["type"] == "A"] if delete_attachments: for item in delete_attachments: att = Attachment.objects.filter(pk=item["id"])[0] if att: att.delete() delete_movements = [x for x in change["delete"] if x["type"] == "M"] if delete_movements: for item in delete_movements: mov = Movement.objects.filter(pk=item["id"])[0] if mov: mov.delete() piece.save() rebuild_suggester_dicts.delay() data = json.dumps({"success": True, "id": piece.id, "url": "/piece/{0}".format(piece.id)}) return HttpResponse(data, content_type="json")