Не создавайте новую версию, если в Django-реверсии ничего не изменилось

Я хотел бы сохранить новую версию объекта, только если что-то изменилось, в django-reversion. Я просмотрел документацию и ничего не нашел по этому поводу. Как мне этого добиться?

1 ответ

Решение

Вы можете использовать ignore_duplicates вариант. к несчастью

Это не следует за отношениями, поскольку это может стать дорогим и медленным очень быстро.

Если вы действительно хотите игнорировать дубликаты для последующих отношений, у вас есть две возможности:

  1. Делай форк и отключай ограничения

Удалить and explicit здесь https://github.com/etianen/django-reversion/blob/master/reversion/revisions.py

Задавать ignore_duplicates как True по умолчанию https://github.com/etianen/django-reversion/blob/master/reversion/revisions.py

Будьте осторожны, как уже упоминалось выше, это может быть медленно.

  1. Прослушайте сигнал подтверждения ревизии и удалите дубликаты версий вручную

Задавать ignore_duplicates как False и добавить приемник сигнала:

from django.db import transaction
from django.dispatch import receiver
from reversion.models import Revision, Version
from reversion.signals import post_revision_commit


def clear_versions(versions, revision):
    count = 0
    for version in versions:
        previous_version = Version.objects.filter(
            object_id=version.object_id,
            content_type_id=version.content_type_id,
            db=version.db,
            id__lt=version.id,
        ).first()
        if not previous_version:
            continue
        if previous_version._local_field_dict == version._local_field_dict:
            version.delete()
            count += 1
        if len(versions_ids) == count:
            revision.delete()


@receiver(post_revision_commit)
def post_revision_commit_receiver(sender, revision, versions, **kwargs):
    transaction.on_commit(lambda: clear_versions(versions, revision))

Это также может быть медленным, но вы можете сделать это асинхронно (например, в задаче Celery):

# tasks.py

@celery.task(time_limit=60, ignore_result=True)
def clear_versions(revision_id, versions_ids):
    count = 0
    if versions_ids:
        for version in Version.objects.filter(id__in=versions_ids):
            previous_version = Version.objects.filter(
                object_id=version.object_id,
                content_type_id=version.content_type_id,
                db=version.db,
                id__lt=version.id,
            ).first()
            if not previous_version:
                continue
            if previous_version._local_field_dict == version._local_field_dict:
                version.delete()
                count += 1
    if len(versions_ids) == count:
        Revision.objects.only('id').get(id=revision_id).delete()

# signals.py

@receiver(post_revision_commit)
def post_revision_commit_receiver(sender, revision, versions, **kwargs):
    transaction.on_commit(
        lambda: clear_versions.delay(revision.id, [v.id for v in versions])
    )
Другие вопросы по тегам