Repository: wagtail/wagtail
File: wagtail/models/reference_index.py (Python)

Code before:

    def describe_source_field(self):
        """
        Returns a string describing the field that this reference was extracted from.

        For StreamField, this returns the label of the block that contains the reference.
        For other fields, this returns the verbose name of the field.
        """
        field = self.source_field
        model_path_components = self.model_path.split(".")

        # ManyToOneRel (reverse accessor for ParentalKey) does not have a verbose name. So get the name of the child field instead
        if isinstance(field, models.ManyToOneRel):
            label = ""
            idx = 2
            child_field = field.related_model._meta.get_field(
                model_path_components[idx]
            )
            while isinstance(child_field, models.ManyToOneRel):
                label += self.get_label(
                    child_field.related_model._meta.verbose_name, idx
                )
                idx += 2
                child_field = field.related_model._meta.get_field(
                    model_path_components[idx]
                )
            label += self.get_label(child_field.verbose_name, idx)
            return label
        elif isinstance(field, StreamField):
            label = f"{capfirst(field.verbose_name)}"
            block = field.stream_block
            block_idx = 1
            while isinstance(block, StreamBlock):
                block = block.child_blocks[model_path_components[block_idx]]
                block_label = capfirst(block.label)
                label += f" → {block_label}"
                block_idx += 1
            return label
        else:
            try:
                field_name = field.verbose_name
            except AttributeError:
                # generate verbose name from field name in the same way that Django does:
                # https://github.com/django/django/blob/7b94847e384b1a8c05a7d4c8778958c0290bdf9a/django/db/models/fields/__init__.py#L858
                field_name = field.name.replace("_", " ")
            return capfirst(field_name)

    def describe_on_delete(self):
        """
        Returns a string describing the action that will be taken when the referenced object is deleted.
        """

Review comment (suggestion):
We'll need the same fix for `describe_on_delete()`, as otherwise we'd be getting the `on_delete` of the first parent.

Code after:
    def related_field(self):
        """
        The final field in which the reference exists.

        The field stored on the reference index can be a related field or a
        reverse related field, depending on whether the reference was extracted
        directly from a ``ForeignKey`` or through a parent ``ClusterableModel``.
        This property normalizes to the related field.
        """
        # Drill through nested inline models to find where the reference exists.
        # Increment idx by 2 each time to skip over the `.item.` component.
        field = self.source_field
        idx = 2
        while isinstance(field, models.ForeignObjectRel):
            related_model_opts = field.related_model._meta
            field = related_model_opts.get_field(self.model_path_components[idx])
            idx += 2
        return field

    @cached_property
    def reverse_related_field(self):
        # This property normalises to the reverse related field, which is where
        # the on_delete attribute is stored.
        return self.related_field.remote_field

    def describe_source_field(self):
        """
        Returns a string describing the field that this reference was extracted from.

        For StreamField, this returns the label of the block that contains the reference.
        For other fields, this returns the verbose name of the field.
        """
        field = self.source_field
        model_path_components = self.model_path_components

        # ManyToOneRel (reverse accessor for ParentalKey) does not have a verbose name,
        # so get the name of the child field instead. While we don't yet support
        # ManyToManyRel, check for ForeignObjectRel (common base class of both
        # ManyToOneRel and ManyToManyRel) to future-proof this.
        if isinstance(field, models.ForeignObjectRel):
            labels = []
            idx = 0
            child_field = field
            while isinstance(child_field, models.ForeignObjectRel):
                related_model_opts = child_field.related_model._meta
                labels.append(capfirst(related_model_opts.verbose_name))
                idx += 2
                child_field = related_model_opts.get_field(model_path_components[idx])
            labels.append(capfirst(child_field.verbose_name))
            return " → ".join(labels)
        elif isinstance(field, StreamField):