def update(self, request, *args, **kwargs):
        # This method is used by bulk update and partial update, but should not
        # be called directly.
        if not kwargs.get('partial', False):
            return self.http_method_not_allowed(request, *args, **kwargs)

        if not request.data:
            return NoEmptyPatchMixin.make_response()

        updatable_keys = set(['acceptance_testing', 'linked_releases', 'rtt_tested_architectures'])
        if set(request.data.keys()) - updatable_keys:
            return Response(status=status.HTTP_400_BAD_REQUEST,
                            data={'detail': 'Only these properties can be updated: %s'
                                  % ', '.join(updatable_keys)})

        arch_testing_status = as_dict(request.data.pop('rtt_tested_architectures', {}),
                                      name='rtt_tested_architectures')
        self.update_arch_testing_status(arch_testing_status)

        old_data = ComposeSerializer(instance=self.get_object(), context={'request': request}).data
        response = super(ComposeViewSet, self).update(request, *args, **kwargs)
        if response.status_code == status.HTTP_200_OK:
            request.changeset.add('Compose', self.object.pk,
                                  json.dumps({'acceptance_testing': old_data['acceptance_testing']}),
                                  json.dumps({'acceptance_testing': response.data['acceptance_testing']}))
            request.changeset.add('Compose', self.object.pk,
                                  json.dumps({'linked_releases': old_data['linked_releases']}),
                                  json.dumps({'linked_releases': response.data['linked_releases']}))
        return response
 def update_arch_testing_status(self, data):
     compose_id = self.kwargs[self.lookup_field]
     for variant_uid in data:
         variant_data = as_dict(data[variant_uid], name=variant_uid)
         for arch_name, status_name in variant_data.iteritems():
             try:
                 var_arch = VariantArch.objects.get(arch__name=arch_name,
                                                    variant__variant_uid=variant_uid,
                                                    variant__compose__compose_id=compose_id)
                 state = ComposeAcceptanceTestingState.objects.get(name=status_name)
             except VariantArch.DoesNotExist:
                 raise serializers.ValidationError(
                     {'rtt_tested_architectures':
                      '%s.%s not in compose %s.' % (variant_uid, arch_name, compose_id)}
                 )
             except ComposeAcceptanceTestingState.DoesNotExist:
                 raise serializers.ValidationError(
                     {'rtt_tested_architectures': '"%s" is not a known testing status for %s.%s.'
                      % (status_name, variant_uid, arch_name)}
                 )
             self.request.changeset.add('ComposeVariantArch', var_arch.pk,
                                        json.dumps({"rtt_testing_status": var_arch.rtt_testing_status.name}),
                                        json.dumps({"rtt_testing_status": status_name}))
             var_arch.rtt_testing_status = state
             var_arch.save()