Merge pull request #13881 from TheRealHaoLiu/fix-copy

Fix copy API
This commit is contained in:
Hao Liu
2023-04-19 09:39:39 -04:00
committed by GitHub
2 changed files with 24 additions and 16 deletions

View File

@@ -5,13 +5,11 @@
import inspect import inspect
import logging import logging
import time import time
import uuid
# Django # Django
from django.conf import settings from django.conf import settings
from django.contrib.auth import views as auth_views from django.contrib.auth import views as auth_views
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.cache import cache
from django.core.exceptions import FieldDoesNotExist from django.core.exceptions import FieldDoesNotExist
from django.db import connection, transaction from django.db import connection, transaction
from django.db.models.fields.related import OneToOneRel from django.db.models.fields.related import OneToOneRel
@@ -967,16 +965,11 @@ class CopyAPIView(GenericAPIView):
if hasattr(new_obj, 'admin_role') and request.user not in new_obj.admin_role.members.all(): if hasattr(new_obj, 'admin_role') and request.user not in new_obj.admin_role.members.all():
new_obj.admin_role.members.add(request.user) new_obj.admin_role.members.add(request.user)
if sub_objs: if sub_objs:
# store the copied object dict into cache, because it's
# often too large for postgres' notification bus
# (which has a default maximum message size of 8k)
key = 'deep-copy-{}'.format(str(uuid.uuid4()))
cache.set(key, sub_objs, timeout=3600)
permission_check_func = None permission_check_func = None
if hasattr(type(self), 'deep_copy_permission_check_func'): if hasattr(type(self), 'deep_copy_permission_check_func'):
permission_check_func = (type(self).__module__, type(self).__name__, 'deep_copy_permission_check_func') permission_check_func = (type(self).__module__, type(self).__name__, 'deep_copy_permission_check_func')
trigger_delayed_deep_copy( trigger_delayed_deep_copy(
self.model.__module__, self.model.__name__, obj.pk, new_obj.pk, request.user.pk, key, permission_check_func=permission_check_func self.model.__module__, self.model.__name__, obj.pk, new_obj.pk, request.user.pk, permission_check_func=permission_check_func
) )
serializer = self._get_copy_return_serializer(new_obj) serializer = self._get_copy_return_serializer(new_obj)
headers = {'Location': new_obj.get_absolute_url(request=request)} headers = {'Location': new_obj.get_absolute_url(request=request)}

View File

@@ -893,15 +893,8 @@ def _reconstruct_relationships(copy_mapping):
@task(queue=get_task_queuename) @task(queue=get_task_queuename)
def deep_copy_model_obj(model_module, model_name, obj_pk, new_obj_pk, user_pk, uuid, permission_check_func=None): def deep_copy_model_obj(model_module, model_name, obj_pk, new_obj_pk, user_pk, permission_check_func=None):
sub_obj_list = cache.get(uuid)
if sub_obj_list is None:
logger.error('Deep copy {} from {} to {} failed unexpectedly.'.format(model_name, obj_pk, new_obj_pk))
return
logger.debug('Deep copy {} from {} to {}.'.format(model_name, obj_pk, new_obj_pk)) logger.debug('Deep copy {} from {} to {}.'.format(model_name, obj_pk, new_obj_pk))
from awx.api.generics import CopyAPIView
from awx.main.signals import disable_activity_stream
model = getattr(importlib.import_module(model_module), model_name, None) model = getattr(importlib.import_module(model_module), model_name, None)
if model is None: if model is None:
@@ -913,6 +906,28 @@ def deep_copy_model_obj(model_module, model_name, obj_pk, new_obj_pk, user_pk, u
except ObjectDoesNotExist: except ObjectDoesNotExist:
logger.warning("Object or user no longer exists.") logger.warning("Object or user no longer exists.")
return return
o2m_to_preserve = {}
fields_to_preserve = set(getattr(model, 'FIELDS_TO_PRESERVE_AT_COPY', []))
for field in model._meta.get_fields():
if field.name in fields_to_preserve:
if field.one_to_many:
try:
field_val = getattr(obj, field.name)
except AttributeError:
continue
o2m_to_preserve[field.name] = field_val
sub_obj_list = []
for o2m in o2m_to_preserve:
for sub_obj in o2m_to_preserve[o2m].all():
sub_model = type(sub_obj)
sub_obj_list.append((sub_model.__module__, sub_model.__name__, sub_obj.pk))
from awx.api.generics import CopyAPIView
from awx.main.signals import disable_activity_stream
with transaction.atomic(), ignore_inventory_computed_fields(), disable_activity_stream(): with transaction.atomic(), ignore_inventory_computed_fields(), disable_activity_stream():
copy_mapping = {} copy_mapping = {}
for sub_obj_setup in sub_obj_list: for sub_obj_setup in sub_obj_list: