PATCH handler for Channel rows. The ``override`` key carries per-field user overrides for auto-created channels and follows these rules: * key absent from payload: no change to existing overrides * ``{"override": {"field": value}}``: upsert those fields
(self, instance, validated_data)
| 608 | return channel |
| 609 | |
| 610 | def update(self, instance, validated_data): |
| 611 | """ |
| 612 | PATCH handler for Channel rows. The ``override`` key carries |
| 613 | per-field user overrides for auto-created channels and follows |
| 614 | these rules: |
| 615 | |
| 616 | * key absent from payload: no change to existing overrides |
| 617 | * ``{"override": {"field": value}}``: upsert those fields |
| 618 | * ``{"override": {"field": null}}``: clear those specific fields |
| 619 | * ``{"override": null}``: delete the override row entirely |
| 620 | |
| 621 | Key presence is what distinguishes "no change" from "delete"; |
| 622 | an explicit null means delete. Override mutations are rejected |
| 623 | on manual channels (auto_created=False) since there is no |
| 624 | provider value to override. |
| 625 | """ |
| 626 | streams = validated_data.pop("streams", None) |
| 627 | has_override_key = "override" in self.initial_data |
| 628 | override_data = validated_data.pop("override", None) |
| 629 | |
| 630 | # Block override mutations on manual channels (no provider |
| 631 | # value to override). Clearing is a tolerated no-op. |
| 632 | if ( |
| 633 | has_override_key |
| 634 | and override_data is not None |
| 635 | and override_data != {} |
| 636 | and not instance.auto_created |
| 637 | ): |
| 638 | raise serializers.ValidationError( |
| 639 | { |
| 640 | "override": ( |
| 641 | "Cannot set override on a manual channel; " |
| 642 | "overrides only apply to auto-created channels." |
| 643 | ) |
| 644 | } |
| 645 | ) |
| 646 | |
| 647 | # Atomic so a failure on the override row rolls back the |
| 648 | # channel update too. |
| 649 | with transaction.atomic(): |
| 650 | # Skip save() when only override keys were submitted; a |
| 651 | # no-op UPDATE would bump updated_at and bust caches. |
| 652 | if validated_data: |
| 653 | for attr, value in validated_data.items(): |
| 654 | setattr(instance, attr, value) |
| 655 | instance.save() |
| 656 | |
| 657 | if has_override_key: |
| 658 | if override_data is None: |
| 659 | # Explicit null: remove the override row. |
| 660 | ChannelOverride.objects.filter(channel=instance).delete() |
| 661 | elif override_data == {}: |
| 662 | # Empty dict has no field intent; no-op. |
| 663 | pass |
| 664 | else: |
| 665 | obj, _ = ChannelOverride.objects.update_or_create( |
| 666 | channel=instance, defaults=override_data |
| 667 | ) |