Example #1
0
def _save_revision(versions,
                   user=None,
                   comment="",
                   meta=(),
                   date_created=None,
                   using=None):
    from reversion.models import Revision
    # Bail early if there are no objects to save.
    if not versions:
        return
    # Save a new revision.
    revision = Revision(
        date_created=date_created,
        user=user,
        comment=comment,
    )
    # Save the revision.
    revision.save(using=using)
    # Save version models.
    for version in versions:
        version.revision = revision
        version.save(using=using)
    # Save the meta information.
    for meta_model, meta_fields in meta:
        meta_model._default_manager.db_manager(using=using).create(
            revision=revision, **meta_fields)
Example #2
0
def _save_revision(versions,
                   user=None,
                   comment="",
                   meta=(),
                   date_created=None,
                   using=None):
    from reversion.models import Revision
    # Only save versions that exist in the database.
    # Use _base_manager so we don't have problems when _default_manager is overriden
    model_db_pks = defaultdict(lambda: defaultdict(set))
    for version in versions:
        model_db_pks[version._model][version.db].add(version.object_id)
    model_db_existing_pks = {
        model: {
            db: frozenset(
                map(
                    force_str,
                    model._base_manager.using(db).filter(
                        pk__in=pks).values_list("pk", flat=True),
                ))
            for db, pks in db_pks.items()
        }
        for model, db_pks in model_db_pks.items()
    }
    versions = [
        version for version in versions if version.object_id in
        model_db_existing_pks[version._model][version.db]
    ]
    # Bail early if there are no objects to save.
    if not versions:
        return
    # Save a new revision.
    revision = Revision(
        date_created=date_created,
        user=user,
        comment=comment,
    )
    # Send the pre_revision_commit signal.
    pre_revision_commit.send(
        sender=create_revision,
        revision=revision,
        versions=versions,
    )
    # Save the revision.
    revision.save(using=using)
    # Save version models.
    for version in versions:
        version.revision = revision
        version.save(using=using)
    # Save the meta information.
    for meta_model, meta_fields in meta:
        meta_model._base_manager.db_manager(using=using).create(
            revision=revision, **meta_fields)
    # Send the post_revision_commit signal.
    post_revision_commit.send(
        sender=create_revision,
        revision=revision,
        versions=versions,
    )
Example #3
0
def update_metric(revision, sender, signal, versions, **kwargs):
    version2 = versions[0]
    fields2 = json.loads(version2.serialized_data)[0]['fields']
    if version2.content_type_id == ContentType.objects.get_for_model(Probe).id:
        version1 = Version.objects.get_for_object(
            Probe.objects.get(id=version2.object_id))[1]

        # getting old probeversion from the second entry in VersionQuerySet
        fields1 = json.loads(version1.serialized_data)[0]['fields']
        old_probeversion = u'%s (%s)' % (fields1['name'], fields1['version'])

        # getting new probeversion from the first entry in VersionQuerySet
        new_probeversion = u'%s (%s)' % (fields2['name'], fields2['version'])

        metric_pk = Metric.objects.filter(
            probeversion=old_probeversion).values_list('id', flat=True)
        ct = ContentType.objects.get_for_model(Metric)

        vers = list()
        for pk in metric_pk:
            instance = Metric.objects.get(id=pk)
            instance.probeversion = new_probeversion
            instance.probekey = version2
            instance.save()
            LogEntry.objects.log_action(user_id=revision.user_id,
                                        content_type_id=ct.id,
                                        object_id=pk,
                                        object_repr=instance.__str__(),
                                        action_flag=CHANGE,
                                        change_message='Changed probeversion.')
            metric_ver = Version.objects.filter(object_id=pk,
                                                content_type_id=ct.id)

            rev = Revision(date_created=revision.date_created,
                           user_id=revision.user_id,
                           comment='[{"changed": {"fields": ['
                           '"probeversion"]}}]')

            ver = Version(object_id=str(instance.id),
                          content_type_id=ct.id,
                          format=metric_ver[0].format,
                          serialized_data=metric_ver[0].serialized_data,
                          object_repr=metric_ver[0].object_repr,
                          db='default')
            rev.save()

            Revision.objects.filter(pk=rev.id).update(
                date_created=revision.date_created)
            ver.revision = rev
            data = json.loads(metric_ver[0].serialized_data)[0]
            data['fields']['probeversion'] = new_probeversion
            data['fields']['probekey'] = version2.id
            ver.serialized_data = json.dumps([data])
            vers.append(ver)

        Version.objects.bulk_create(vers)
 def save_revision(self, objects, ignore_duplicates=False, user=None, comment="", meta=(), db=None):
     """Saves a new revision."""
     # Get the db alias.
     db = db or DEFAULT_DB_ALIAS
     # Adapt the objects to a dict.
     if isinstance(objects, (list, tuple)):
         objects = dict(
             (obj, self.get_adapter(obj.__class__).get_version_data(obj, VERSION_CHANGE, db)) for obj in objects
         )
     # Create the revision.
     if objects:
         # Follow relationships.
         for obj in self._follow_relationships(objects.iterkeys()):
             if not obj in objects:
                 adapter = self.get_adapter(obj.__class__)
                 objects[obj] = adapter.get_version_data(obj, VERSION_CHANGE)
         # Create all the versions without saving them
         ordered_objects = list(objects.iterkeys())
         new_versions = [Version(**objects[obj]) for obj in ordered_objects]
         # Check if there's some change in all the revision's objects.
         save_revision = True
         if ignore_duplicates:
             # Find the latest revision amongst the latest previous version of each object.
             subqueries = [
                 Q(object_id=version.object_id, content_type=version.content_type) for version in new_versions
             ]
             subqueries = reduce(operator.or_, subqueries)
             latest_revision = self._get_versions(db).filter(subqueries).aggregate(Max("revision"))["revision__max"]
             # If we have a latest revision, compare it to the current revision.
             if latest_revision is not None:
                 previous_versions = (
                     self._get_versions(db)
                     .filter(revision=latest_revision)
                     .values_list("serialized_data", flat=True)
                 )
                 if len(previous_versions) == len(new_versions):
                     all_serialized_data = [version.serialized_data for version in new_versions]
                     if sorted(previous_versions) == sorted(all_serialized_data):
                         save_revision = False
         # Only save if we're always saving, or have changes.
         if save_revision:
             # Save a new revision.
             revision = Revision(manager_slug=self._manager_slug, user=user, comment=comment)
             # Send the pre_revision_commit signal.
             pre_revision_commit.send(self, instances=ordered_objects, revision=revision, versions=new_versions)
             # Save the revision.
             revision.save(using=db)
             # Save version models.
             for version in new_versions:
                 version.revision = revision
                 version.save(using=db)
             # Save the meta information.
             for cls, kwargs in meta:
                 cls._default_manager.db_manager(db).create(revision=revision, **kwargs)
             # Send the pre_revision_commit signal.
             post_revision_commit.send(self, instances=ordered_objects, revision=revision, versions=new_versions)
Example #5
0
def _save_revision(versions, user=None, comment="", meta=(), date_created=None, using=None):
    from reversion.models import Revision
    # Only save versions that exist in the database.
    # Use _base_manager so we don't have problems when _default_manager is overriden
    model_db_pks = defaultdict(lambda: defaultdict(set))
    for version in versions:
        model_db_pks[version._model][version.db].add(version.object_id)
    model_db_existing_pks = {
        model: {
            db: frozenset(map(
                force_text,
                model._base_manager.using(db).filter(pk__in=pks).values_list("pk", flat=True),
            ))
            for db, pks in db_pks.items()
        }
        for model, db_pks in model_db_pks.items()
    }
    versions = [
        version for version in versions
        if version.object_id in model_db_existing_pks[version._model][version.db]
    ]
    # Bail early if there are no objects to save.
    if not versions:
        return
    # Save a new revision.
    revision = Revision(
        date_created=date_created,
        user=user,
        comment=comment,
    )
    # Send the pre_revision_commit signal.
    pre_revision_commit.send(
        sender=create_revision,
        revision=revision,
        versions=versions,
    )
    # Save the revision.
    revision.save(using=using)
    # Save version models.
    for version in versions:
        version.revision = revision
        version.save(using=using)
    # Save the meta information.
    for meta_model, meta_fields in meta:
        meta_model._base_manager.db_manager(using=using).create(
            revision=revision,
            **meta_fields
        )
    # Send the post_revision_commit signal.
    post_revision_commit.send(
        sender=create_revision,
        revision=revision,
        versions=versions,
    )
    def save_revision(self, objects, user=None, comment='', meta=(), db=None):
        """Saves a new revision."""
        # Create the revision.
        if objects:
            # Follow relationships.
            for obj, follower_type in self._follow_relationships(
                    ((key, version_data.get('type')) for key, version_data in objects.items())
                ):
                if not obj in objects:
                    adapter = self.get_adapter(obj.__class__)
                    follow_obj_data = adapter.get_version_data(obj)
                    follow_obj_data['type'] = follower_type
                    objects[obj] = follow_obj_data

            # Create all the versions without saving them
            ordered_objects = list(objects.keys())
            new_versions = [Version(**objects[obj]) for obj in ordered_objects]
            # Check if there's some change in all the revision's objects.
            save_revision = True
            # Only save if we're always saving, or have changes.
            if save_revision:
                # Save a new revision.
                revision = Revision(
                    manager_slug = self._manager_slug,
                    user = user,
                    comment = comment,
                )
                # Send the pre_revision_commit signal.
                pre_revision_commit.send(self,
                    instances = ordered_objects,
                    revision = revision,
                    versions = new_versions,
                )
                # Save the revision.
                with transaction.atomic(using=db):
                    revision.save(using=db)
                    # Save version models.
                    for version in new_versions:
                        version.revision = revision
                        version.save()
                    # Save the meta information.
                    for cls, kwargs in meta:
                        cls._default_manager.db_manager(db).create(revision=revision, **kwargs)
                # Send the post_revision_commit signal.
                post_revision_commit.send(self,
                    instances = ordered_objects,
                    revision = revision,
                    versions = new_versions,
                )
                # Return the revision.
                return revision
Example #7
0
def _save_revision(versions, user=None, comment="", meta=(), date_created=None, using=None):
    from reversion.models import Revision
    # Bail early if there are no objects to save.
    if not versions:
        return
    # Save a new revision.
    revision = Revision(
        date_created=date_created,
        user=user,
        comment=comment,
    )
    # Save the revision.
    revision.save(using=using)
    # Save version models.
    for version in versions:
        version.revision = revision
        version.save(using=using)
    # Save the meta information.
    for meta_model, meta_fields in meta:
        meta_model._default_manager.db_manager(using=using).create(
            revision=revision,
            **meta_fields
        )
Example #8
0
def _save_revision(versions, user=None, comment="", meta=(), date_created=None, using=None):
    from reversion.models import Revision
    # Bail early if there are no objects to save.
    if not versions:
        return
    # Save a new revision.
    with transaction.atomic(using=using):  # altered from original. Normally _save_revision is run wintin atomic context
        revision = Revision(
            date_created=date_created,
            user=user,
            comment=comment,
        )
        # Send the pre_revision_commit signal.
        pre_revision_commit.send(
            sender=create_revision,
            revision=revision,
            versions=versions,
        )
        # Save the revision.
        revision.save(using=using)
        # Save version models.
        for version in versions:
            version.revision = revision
            version.save(using=using)
        # Save the meta information.
        for meta_model, meta_fields in meta:
            meta_model._default_manager.db_manager(using=using).create(
                revision=revision,
                **meta_fields
            )
        # Send the post_revision_commit signal.
        post_revision_commit.send(
            sender=create_revision,
            revision=revision,
            versions=versions,
        )
Example #9
0
 def save_revision(self, objects, ignore_duplicates=False, user=None, comment="", meta=(), db=None):
     """Saves a new revision."""
     # Get the db alias.
     db = db or DEFAULT_DB_ALIAS
     # Adapt the objects to a dict.
     if isinstance(objects, (list, tuple)):
         objects = dict(
             (obj, self.get_adapter(obj.__class__).get_version_data(obj, db))
             for obj in objects
         )
     # Create the revision.
     if objects:
         # Follow relationships.
         for obj in self._follow_relationships(objects.keys()):
             if not obj in objects:
                 adapter = self.get_adapter(obj.__class__)
                 objects[obj] = adapter.get_version_data(obj)
         # Create all the versions without saving them
         ordered_objects = list(objects.keys())
         new_versions = [Version(**objects[obj]) for obj in ordered_objects]
         # Check if there's some change in all the revision's objects.
         save_revision = True
         if ignore_duplicates:
             # Find the latest revision amongst the latest previous version of each object.
             subqueries = [Q(object_id=version.object_id, content_type=version.content_type) for version in new_versions]
             subqueries = reduce(operator.or_, subqueries)
             latest_revision = self._get_versions(db).filter(subqueries).aggregate(Max("revision"))["revision__max"]
             # If we have a latest revision, compare it to the current revision.
             if latest_revision is not None:
                 previous_versions = self._get_versions(db).filter(revision=latest_revision).values_list("serialized_data", flat=True)
                 if len(previous_versions) == len(new_versions):
                     all_serialized_data = [version.serialized_data for version in new_versions]
                     if sorted(previous_versions) == sorted(all_serialized_data):
                         save_revision = False
         # Only save if we're always saving, or have changes.
         if save_revision:
             # Save a new revision.
             revision = Revision(
                 manager_slug = self._manager_slug,
                 user = user,
                 comment = comment,
             )
             # Send the pre_revision_commit signal.
             pre_revision_commit.send(self,
                 instances = ordered_objects,
                 revision = revision,
                 versions = new_versions,
             )
             # Save the revision.
             with transaction.atomic(using=db):
                 revision.save(using=db)
                 # Save version models.
                 for version in new_versions:
                     version.revision = revision
                 Version.objects.using(db).bulk_create(new_versions)
                 # Save the meta information.
                 for cls, kwargs in meta:
                     cls._default_manager.db_manager(db).create(revision=revision, **kwargs)
             # Send the pre_revision_commit signal.
             post_revision_commit.send(self,
                 instances = ordered_objects,
                 revision = revision,
                 versions = new_versions,
             )
             # Return the revision.
             return revision
 def save_revision(self, objects, updated=None, inserted=None, deleted=None, ignore_duplicates=False, user=None,
                   comment="", smart=True, meta=(), db=None):
     """Saves a new revision."""
     request = current_task.request
     logger.info("Executing task id {id}, args: {args} retries: {retries}".format(
         id=request.id, args=request.args, retries=request.retries))
     logger.info(request.kwargs)
     # Get the db alias.
     db = db or DEFAULT_DB_ALIAS
     # Adapt the objects to a dict.
     if isinstance(objects, (list, tuple)):
         objects = dict(
             (obj, self.get_adapter(obj.__class__).get_version_data(obj, VERSION_CHANGE, db))
             for obj in objects
         )
     # Create the revision.
     if objects:
         # Follow relationships.
         for obj in self._follow_relationships(objects.keys()):
             if not obj in objects:
                 adapter = self.get_adapter(obj.__class__)
                 objects[obj] = adapter.get_version_data(obj, VERSION_CHANGE)
         # Create all the versions without saving them
         ordered_objects = list(objects.keys())
         new_versions = [Version(**objects[obj]) for obj in ordered_objects]
         # Check if there's some change in all the revision's objects.
         save_revision = True
         if ignore_duplicates:
             # Find the latest revision amongst the latest previous version of each object.
             subqueries = [Q(object_id=version.object_id, content_type=version.content_type)
                           for version in new_versions]
             subqueries = reduce(operator.or_, subqueries)
             latest_revision = self._get_versions(db).filter(subqueries).aggregate(Max("revision"))["revision__max"]
             # If we have a latest revision, compare it to the current revision.
             if latest_revision is not None:
                 previous_versions = (self._get_versions(db).filter(revision=latest_revision)
                                      .values_list("serialized_data", flat=True))
                 if len(previous_versions) == len(new_versions):
                     all_serialized_data = [version.serialized_data for version in new_versions]
                     if sorted(previous_versions) == sorted(all_serialized_data):
                         save_revision = False
         # Only save if we're always saving, or have changes.
         if save_revision:
             # Save a new revision.
             if not comment and smart:
                 deleted_comments, inserted_comments, updated_comments = [], [], []
                 for deleted_instance in deleted:
                     deleted_comments.append(was_deleted_message.format(get_object_smart_repr(deleted_instance)))
                 for inserted_instance in inserted:
                     #here we must get the instances what was created
                     inserted_comments.append(was_created_message.format(get_object_smart_repr(inserted_instance)))
                 for serialized_updated_instance in updated:
                     old_instance_deserialized = deserialize(VersionAdapter.format,
                                                             serialized_updated_instance).next()
                     new_instance = None
                     change_list = []
                     for instance in objects:
                         if (old_instance_deserialized.object.__class__ == instance.__class__
                                 and old_instance_deserialized.object.pk == instance.pk):
                             new_instance = instance
                             break
                     fields = sorted(new_instance._meta.fields + new_instance._meta.many_to_many,
                                     key=lambda x: x.creation_counter)
                     exclude_fields = self.get_adapter(new_instance.__class__).exclude
                     fields = [field for field in fields if field.name not in exclude_fields]
                     for field in fields:
                         old_value, new_value = (field.value_from_object(old_instance_deserialized.object),
                                                 field.value_from_object(new_instance))
                         # Set false old and new values to None because of next != operator(types..)
                         if not old_value:
                             old_value = None
                         if not new_value:
                             new_value = None
                         if old_value != new_value:
                             if not isinstance(field, (AutoField, ManyToManyField)):
                                     if isinstance(field, RelatedField):
                                         if old_value:
                                             value_from = get_object_smart_repr(field.rel.to.objects.get(pk=old_value))
                                         else:
                                             value_from = no_value_message
                                         if new_value:
                                             value_to = get_object_smart_repr(field.rel.to.objects.get(pk=new_value))
                                         else:
                                             value_to = no_value_message
                                         change_list.append(changes_template.format(verbose_name=field.verbose_name,
                                                                                    value_from=value_from,
                                                                                    value_to=value_to))
                                     else:
                                         value_from = old_value if old_value else no_value_message
                                         value_to = new_value if new_value else no_value_message
                                         change_list.append(changes_template.format(verbose_name=field.verbose_name,
                                                                                    value_from=value_from,
                                                                                    value_to=value_to))
                             elif isinstance(field, ManyToManyField):
                                 old_value = old_instance_deserialized.m2m_data[field.name]
                                 old_value = [int(pk) for pk in old_value] if old_value else old_value
                                 new_value = [obj.pk for obj in new_value] if new_value else new_value
                                 if old_value:
                                     value_from = u", ".join(get_object_smart_repr(field.rel.to.objects.get(pk=m2m_pk))
                                                             for m2m_pk in old_value)
                                 else:
                                     value_from = no_value_message
                                 if new_value:
                                     value_to = u", ".join(get_object_smart_repr(field.rel.to.objects.get(pk=m2m_pk))
                                                           for m2m_pk in new_value)
                                 else:
                                     value_to = no_value_message
                                 if old_value != new_value:
                                     change_list.append(changes_template.format(verbose_name=field.verbose_name,
                                                                                value_from=value_from,
                                                                                value_to=value_to))
                     if change_list:
                         object_repr = get_object_smart_repr(old_instance_deserialized.object)
                         change_list.insert(0, was_changed_message.format(object_repr))
                     if change_list:
                         inserted_comments_string = u"\n".join(change_list)
                     else:
                         new_instance_repr = get_object_smart_repr(new_instance)
                         inserted_comments_string = saved_without_changes_message.format(new_instance_repr)
                     inserted_comments.append(inserted_comments_string)
                 comment = u"\n".join(inserted_comments + updated_comments + deleted_comments)
             revision = Revision(
                 manager_slug=self._manager_slug,
                 user=user,
                 user_string=unicode(user) if user else u"",
                 comment=comment,
             )
             # Send the pre_revision_commit signal.
             pre_revision_commit.send(self,
                                      instances=ordered_objects,
                                      revision=revision,
                                      versions=new_versions)
             # Save the revision.
             revision.save(using=db)
             # Save version models.
             for version in new_versions:
                 version.revision = revision
                 version.save(using=db)
             # Save the meta information.
             for cls, kwargs in meta:
                 cls._default_manager.db_manager(db).create(revision=revision, **kwargs)
             # Send the pre_revision_commit signal.
             post_revision_commit.send(self,
                                       instances=ordered_objects,
                                       revision=revision,
                                       versions=new_versions,)
             # Return the revision.
             return revision
Example #11
0
 def get_comment(self, revision: Revision):
     return revision.get_comment()
Example #12
0
def _save_revision(versions,
                   user=None,
                   comment="",
                   meta=(),
                   date_created=None,
                   using=None):
    from reversion.models import Revision
    # Only save versions that exist in the database.
    # Use _base_manager so we don't have problems when _default_manager is overriden
    model_db_pks = defaultdict(lambda: defaultdict(set))
    for version in versions:
        model_db_pks[version._model][version.db].add(version.object_id)
    model_db_existing_pks = {
        model: {
            db: frozenset(
                map(
                    force_str,
                    model._base_manager.using(db).filter(
                        pk__in=pks).values_list("pk", flat=True),
                ))
            for db, pks in db_pks.items()
        }
        for model, db_pks in model_db_pks.items()
    }
    versions = [
        version for version in versions if version.object_id in
        model_db_existing_pks[version._model][version.db]
    ]
    # Bail early if there are no objects to save.
    if not versions:
        return
    # Save a new revision.
    revision = Revision(
        date_created=date_created,
        user=user,
        comment=comment,
    )
    # Send the pre_revision_commit signal.
    pre_revision_commit.send(
        sender=create_revision,
        revision=revision,
        versions=versions,
    )
    # Save the revision.
    revision.save(using=using)
    # Save version models.
    for version in versions:
        version.revision = revision
        version.save(using=using)
    # Save the meta information.
    for meta_inst_or_model, meta_fields in meta:

        # Default meta class and primary key
        meta_class = meta_inst_or_model
        pk = None

        # Add the revision to the fields that will be added/updated
        meta_fields['revision'] = revision

        # If the supplied meta_model is an instance, we need to ensure the
        # correct class is used when updating as well as be able to query
        # the meta instance properly
        if isinstance(meta_inst_or_model, (models.Model, )):
            # Fetch the class used to make the update
            meta_class = meta_inst_or_model.__class__
            pk = meta_inst_or_model.pk

        # Call update or create
        meta_class._base_manager.db_manager(using=using).update_or_create(
            pk=pk, defaults=meta_fields)

    # Send the post_revision_commit signal.
    post_revision_commit.send(
        sender=create_revision,
        revision=revision,
        versions=versions,
    )
Example #13
0
def _save_revision(versions, user=None, comment="", meta=(), date_created=None, using=None):
    from reversion.models import Revision
    # Only save versions that exist in the database.
    model_db_pks = defaultdict(lambda: defaultdict(set))
    for version in versions:
        model_db_pks[version._model][version.db].add(version.object_id)
    model_db_existing_pks = {
        model: {
            db: frozenset(map(
                force_text,
                model._default_manager.using(db).filter(pk__in=pks).values_list("pk", flat=True),
            ))
            for db, pks in db_pks.items()
            }
        for model, db_pks in model_db_pks.items()
        }
    custom_models = getattr(settings, 'DJANGO_REVISION_CUSTOM_MODELS', False)

    if custom_models:
        if hasattr(settings, 'DJANGO_REVISION_EXCLUDED_MODELS'):
            versions = [
                version for version in versions
                if version._model._meta.object_name not in settings.DJANGO_REVISION_EXCLUDED_MODELS and
                version.object_id in model_db_existing_pks[version._model][version.db]
                ]
        elif hasattr(settings, 'DJANGO_REVISION_ALLOWED_MODELS'):
            versions = [
                version for version in versions
                if version._model._meta.object_name in settings.DJANGO_REVISION_ALLOWED_MODELS and
                version.object_id in model_db_existing_pks[version._model][version.db]
                ]
        else:
            raise ImproperlyConfigured(
                "Using 'DJANGO_REVISION_CUSTOM_MODELS' without either the 'DJANGO_REVISION_EXCLUDED_MODELS' in"
                " settings or the 'DJANGO_REVISION_ALLOWED_MODELS' in settings is prohibited.")
    else:
        versions = [
            version for version in versions
            if version.object_id in model_db_existing_pks[version._model][version.db]
            ]
    # Bail early if there are no objects to save.
    if not versions:
        return
    # Save a new revision.
    revision = Revision(
        date_created=date_created,
        user=user,
        comment=comment,
    )
    # Send the pre_revision_commit signal.
    pre_revision_commit.send(
        sender=create_revision,
        revision=revision,
        versions=versions,
    )
    # Save the revision.
    revision.save(using=using)
    # Save version models.
    for version in versions:
        version.revision = revision
        version.save(using=using)
    # Save the meta information.
    for meta_model, meta_fields in meta:
        meta_model._default_manager.db_manager(using=using).create(
            revision=revision,
            **meta_fields
        )
    # Send the post_revision_commit signal.
    post_revision_commit.send(
        sender=create_revision,
        revision=revision,
        versions=versions,
    )
Example #14
0
def _save_revision(versions,
                   user=None,
                   comment="",
                   meta=(),
                   date_created=None,
                   using=None):
    from reversion.models import Revision
    # Only save versions that exist in the database.
    model_db_pks = defaultdict(lambda: defaultdict(set))
    for version in versions:
        model_db_pks[version._model][version.db].add(version.object_id)
    model_db_existing_pks = {
        model: {
            db: frozenset(
                map(
                    force_text,
                    model._default_manager.using(db).filter(
                        pk__in=pks).values_list("pk", flat=True),
                ))
            for db, pks in db_pks.items()
        }
        for model, db_pks in model_db_pks.items()
    }
    versions = [
        version for version in versions if version.object_id in
        model_db_existing_pks[version._model][version.db]
    ]
    # Bail early if there are no objects to save.
    if not versions:
        return
    # Save a new revision.
    revision = Revision(
        date_created=date_created,
        user=user,
        comment=comment,
    )
    # Send the pre_revision_commit signal.
    pre_revision_commit.send(
        sender=create_revision,
        revision=revision,
        versions=versions,
    )
    # Save the revision.
    revision.save(using=using)
    # Save version models.
    # XXX magic numbers because base content needs to be saved before children
    BASE_CONTENT_TYPE_ID = 18
    versions = sorted(
        versions,
        key=lambda v:
        (0
         if v.content_type_id == BASE_CONTENT_TYPE_ID else v.content_type_id))
    for version in versions:
        version.revision = revision
        version.save(using=using)
    # Save the meta information.
    for meta_model, meta_fields in meta:
        meta_model._default_manager.db_manager(using=using).create(
            revision=revision, **meta_fields)
    # Send the post_revision_commit signal.
    post_revision_commit.send(
        sender=create_revision,
        revision=revision,
        versions=versions,
    )
Example #15
0
def _save_revision(versions,
                   user=None,
                   comment="",
                   meta=(),
                   date_created=None,
                   using=None):
    from reversion.models import Revision
    # Only save versions that exist in the database.
    # Use _base_manager so we don't have problems when _default_manager is overriden
    model_db_pks = defaultdict(lambda: defaultdict(set))
    for version in versions:
        model_db_pks[version._model][version.db].add(version.object_id)

    def _safe_get_pks(model, db, pks):
        """
        Hack: helper function for use with django-safedelete package
        so we avoid committing versions for objects that have already
        been safe deleted

        See hack in models VersionQuerySet get_deleted too
        """
        try:
            from safedelete.models import is_safedelete_cls
        except ImportError:
            is_safedelete_cls = lambda: False

        if is_safedelete_cls(model):
            # Use the safedelete manager to ensure we exclude "soft-deleted"
            # obj versions
            return model._default_manager.using(db).filter(pk__in=pks)\
                .values_list("pk", flat=True)
        # Else: not using softdelete for this model so use base manager as in
        # original django-revision
        return model._base_manager.using(db).filter(pk__in=pks)\
            .values_list("pk", flat=True)

    model_db_existing_pks = {
        model: {
            db: frozenset(map(
                force_text,
                _safe_get_pks(model, db, pks),
            ))
            for db, pks in db_pks.items()
        }
        for model, db_pks in model_db_pks.items()
    }
    versions = [
        version for version in versions if version.object_id in
        model_db_existing_pks[version._model][version.db]
    ]
    # Bail early if there are no objects to save.
    if not versions:
        return
    # Save a new revision.
    revision = Revision(
        date_created=date_created,
        user=user,
        comment=comment,
    )
    # Send the pre_revision_commit signal.
    pre_revision_commit.send(
        sender=create_revision,
        revision=revision,
        versions=versions,
    )
    # Save the revision.
    revision.save(using=using)
    # Save version models.
    for version in versions:
        version.revision = revision
        version.save(using=using)
    # Save the meta information.
    for meta_model, meta_fields in meta:
        meta_model._base_manager.db_manager(using=using).create(
            revision=revision, **meta_fields)
    # Send the post_revision_commit signal.
    post_revision_commit.send(
        sender=create_revision,
        revision=revision,
        versions=versions,
    )
Example #16
0
    def save_revision(self, objects=(), ignore_duplicates=False, user=None, comment="", meta=(),
                      date_created=None, db=None):
        """
        Manually saves a new revision containing the given objects.

        `objects` is an iterable of model instances.
        `serialized_objects` is an iterable of dicts of version data.
        """
        from django.contrib.contenttypes.models import ContentType
        from reversion.models import Revision, Version
        date_created = timezone.now() if date_created is None else date_created
        # Create the object versions.
        version_data_dict = {}
        for obj in objects:
            # Handle eagerly-saved version dicts.
            if isinstance(obj, dict):
                version_data_seq = (obj,)
            # Handle model instances.
            else:
                version_data_seq = (
                    self.get_adapter(relation.__class__).get_version_data(relation)
                    for relation
                    in self._follow_relationships(obj)
                )
            # Store the version data.
            version_data_dict.update(
                ((version_data["content_type"], version_data["object_id"]), version_data)
                for version_data
                in version_data_seq
            )
        new_versions = [
            Version(
                content_type=ContentType.objects.db_manager(db).get_by_natural_key(*version_data["content_type"]),
                object_id=version_data["object_id"],
                db=version_data["db"],
                format=version_data["format"],
                serialized_data=version_data["serialized_data"],
                object_repr=version_data["object_repr"],
            )
            for version_data
            in version_data_dict.values()
        ]
        # Bail early if there are no objects to save.
        if not new_versions:
            return
        # Check for duplicates, if requested.
        save_revision = True
        if ignore_duplicates:
            # Find the latest revision amongst the latest previous version of each object.
            latest_revision_qs = Revision.objects.using(db).annotate(
                version_count=models.Count("version"),
            ).filter(
                version_count=len(new_versions),
                manager_slug=self._manager_slug,
            )
            for version in new_versions:
                latest_revision_qs = latest_revision_qs.filter(
                    version__object_id=version.object_id,
                    version__content_type_id=version.content_type_id,
                    version__db=version.db,
                )
            latest_revision = latest_revision_qs.order_by("-pk").first()
            # If we have a latest revision, compare it to the current revision.
            if latest_revision is not None:
                previous_versions = latest_revision.version_set.all()

                # Creates a sorted list of version keys for comparison.
                def get_version_keys(versions):
                    return [
                        (version.object_id, version.content_type_id, version.db, version.local_field_dict)
                        for version
                        in sorted(versions, key=lambda v: (v.object_id, v.content_type_id, v.db))
                    ]
                save_revision = get_version_keys(previous_versions) != get_version_keys(new_versions)
        # Only save if we're always saving, or have changes.
        if save_revision:
            # Save a new revision.
            revision = Revision(
                manager_slug=self._manager_slug,
                date_created=date_created,
                user=user,
                comment=comment,
            )
            # Send the pre_revision_commit signal.
            pre_revision_commit.send(
                sender=self,
                instances=objects,
                revision=revision,
                versions=new_versions,
            )
            # Save the revision.
            with transaction.atomic(using=db):
                revision.save(using=db)
                # Save version models.
                for version in new_versions:
                    version.revision = revision
                    version.save(using=db)
                # Save the meta information.
                for meta_obj in meta:
                    meta_obj.revision = revision
                    meta_obj.save(using=db)
            # Send the post_revision_commit signal.
            post_revision_commit.send(
                sender=self,
                instances=objects,
                revision=revision,
                versions=new_versions,
            )
            # Return the revision.
            return revision