# Buggy code
def handle(self, *args, **options):
    current_page_id = None
    missing_models_content_type_ids = set()
    for revision in (
        PageRevision.objects.order_by("page_id", "created_at")
        .select_related("page")
        .iterator()
    ):
        # This revision is for a page type that is no longer in the database. Bail out early.
        if revision.page.content_type_id in missing_models_content_type_ids:
            continue
        if not revision.page.specific_class:
            missing_models_content_type_ids.add(revision.page.content_type_id)
            continue

        is_new_page = revision.page_id != current_page_id
        if is_new_page:
            # reset previous revision when encountering a new page.
            previous_revision = None

        has_content_changes = False
        current_page_id = revision.page_id

        if not PageLogEntry.objects.filter(revision=revision).exists():
            current_revision_as_page = revision.as_page_object()
            published = revision.id == revision.page.live_revision_id

            if previous_revision is not None:
                # Must use .specific so the comparison picks up all fields, not just base Page ones.
                comparison = get_comparison(
                    revision.page.specific,
                    previous_revision.as_page_object(),
                    current_revision_as_page,
                )
                has_content_changes = len(comparison) > 0

                if current_revision_as_page.live_revision_id == previous_revision.id:
                    # Log the previous revision publishing.
                    self.log_page_action("wagtail.publish", previous_revision, True)

            if is_new_page or has_content_changes or published:
                if is_new_page:
                    action = "wagtail.create"
                elif published:
                    action = "wagtail.publish"
                else:
                    action = "wagtail.edit"

                if published and has_content_changes:
                    # When publishing, also log the 'draft save', but only if there have been content changes
                    self.log_page_action("wagtail.edit", revision, has_content_changes)

                self.log_page_action(action, revision, has_content_changes)

        previous_revision = revision


# Traceback (Exception)
Traceback (most recent call last):
File "./cfgov/manage.py", line 11, in <module>
execute_from_command_line(sys.argv)
File "/Users/higginsw/.pyenv/versions/c15gov/lib/python3.6/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line
utility.execute()
File "/Users/higginsw/.pyenv/versions/c15gov/lib/python3.6/site-packages/django/core/management/__init__.py", line 375, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/Users/higginsw/.pyenv/versions/c15gov/lib/python3.6/site-packages/django/core/management/base.py", line 323, in run_from_argv
self.execute(*args, **cmd_options)
File "/Users/higginsw/.pyenv/versions/c15gov/lib/python3.6/site-packages/django/core/management/base.py", line 364, in execute
output = self.handle(*args, **options)
File "/Users/higginsw/.pyenv/versions/c15gov/lib/python3.6/site-packages/wagtail/core/management/commands/create_log_entries_from_revisions.py", line 34, in handle
current_revision_as_page = revision.as_page_object()
File "/Users/higginsw/.pyenv/versions/c15gov/lib/python3.6/site-packages/wagtail/core/models.py", line 1977, in as_page_object
return self.page.specific.with_content_json(self.content_json)
File "/Users/higginsw/.pyenv/versions/c15gov/lib/python3.6/site-packages/wagtail/core/models.py", line 1830, in with_content_json
obj = self.specific_class.from_json(content_json)
File "/Users/higginsw/.pyenv/versions/c15gov/lib/python3.6/site-packages/modelcluster/models.py", line 272, in from_json
return cls.from_serializable_data(json.loads(json_data), check_fks=check_fks, strict_fks=strict_fks)
File "/Users/higginsw/.pyenv/versions/c15gov/lib/python3.6/site-packages/modelcluster/models.py", line 239, in from_serializable_data
obj = model_from_serializable_data(cls, data, check_fks=check_fks, strict_fks=strict_fks)
File "/Users/higginsw/.pyenv/versions/c15gov/lib/python3.6/site-packages/modelcluster/models.py", line 100, in model_from_serializable_data
raise Exception("can't currently handle on_delete types other than CASCADE, SET_NULL and DO_NOTHING")
Exception: can't currently handle on_delete types other than CASCADE, SET_NULL and DO_NOTHING

# Fixed code
def handle(self, *args, **options):
    current_page_id = None
    missing_models_content_type_ids = set()
    for revision in (
        PageRevision.objects.order_by("page_id", "created_at")
        .select_related("page")
        .iterator()
    ):
        # This revision is for a page type that is no longer in the database. Bail out early.
        if revision.page.content_type_id in missing_models_content_type_ids:
            continue
        if not revision.page.specific_class:
            missing_models_content_type_ids.add(revision.page.content_type_id)
            continue

        is_new_page = revision.page_id != current_page_id
        if is_new_page:
            # reset previous revision when encountering a new page.
            previous_revision = None

        has_content_changes = False
        current_page_id = revision.page_id

        if not PageLogEntry.objects.filter(revision=revision).exists():
            try:
                current_revision_as_page = revision.as_page_object()
            except Exception:
                # restoring old revisions may fail if e.g. they have an on_delete=PROTECT foreign key
                # to a no-longer-existing model instance. We cannot compare changes between two
                # non-restorable revisions, although we can at least infer that there was a content
                # change at the point that it went from restorable to non-restorable or vice versa.
                current_revision_as_page = None

            published = revision.id == revision.page.live_revision_id

            if previous_revision is not None:
                try:
                    previous_revision_as_page = previous_revision.as_page_object()
                except Exception:
                    previous_revision_as_page = None

                if (
                    previous_revision_as_page is None
                    and current_revision_as_page is None
                ):
                    # both revisions failed to restore - unable to determine presence of content changes
                    has_content_changes = False
                elif (
                    previous_revision_as_page is None
                    or current_revision_as_page is None
                ):
                    # one or the other revision failed to restore, which indicates a content change
                    has_content_changes = True
                else:
                    # Must use .specific so the comparison picks up all fields, not just base Page ones.
                    comparison = get_comparison(
                        revision.page.specific,
                        previous_revision_as_page,
                        current_revision_as_page,
                    )
                    has_content_changes = len(comparison) > 0

                if current_revision_as_page.live_revision_id == previous_revision.id:
                    # Log the previous revision publishing.
                    self.log_page_action("wagtail.publish", previous_revision, True)

            if is_new_page or has_content_changes or published:
                if is_new_page:
                    action = "wagtail.create"
                elif published:
                    action = "wagtail.publish"
                else:
                    action = "wagtail.edit"

                if published and has_content_changes:
                    # When publishing, also log the 'draft save', but only if there have been content changes
                    self.log_page_action("wagtail.edit", revision, has_content_changes)

                self.log_page_action(action, revision, has_content_changes)

        previous_revision = revision