Repository: django/django
File: django/core/serializers/base.py (Python)

Code before:
            return self.stream.getvalue()

    def _resolve_fk_natural_key(self, obj, field):
        """
        Return the natural key for a ForeignKey's related object, or None if
        not supported.
        """
        if not self._model_supports_natural_key(field.remote_field.model):
            return None

        related = getattr(obj, field.name, None)
        try:
            return related.natural_key()
        except AttributeError:
            return None

    def _instance_supports_natural_key(self, obj):
        """Return True if the instance defines a non-empty natural_key()."""
        try:
            return bool(obj.natural_key())
        except AttributeError:
            return False

    def _model_supports_natural_key(self, model):
        """Return True if the model defines a non-empty natural_key()."""
        return self._instance_supports_natural_key(model())


class Deserializer:
    """
    Abstract base deserializer class.
    """

    def __init__(self, stream_or_string, **options):
        """
        Init this serializer given a stream or a string
        """
        self.options = options
        if isinstance(stream_or_string, str):
            self.stream = StringIO(stream_or_string)
        else:
            self.stream = stream_or_string

    def __iter__(self):
        return self

    def __next__(self):
        """Iteration interface -- return the next item in the stream"""
        raise NotImplementedError(
            "subclasses of Deserializer must provide a __next__() method"
        )

Review comment (refactor):
I went too far. I now see why you needed to call `natural_key()` on each object during the many-to-many iterator. Will restore your helper for that. 😅 

Code after:
            return self.stream.getvalue()

    def _resolve_natural_key(self, obj):
        """Return a natural key tuple for the given object when available."""
        try:
            return obj.natural_key()
        except AttributeError:
            return None

    def _resolve_fk_natural_key(self, obj, field):
        """
        Return the natural key for a ForeignKey's related object, or None if
        not supported.
        """
        if not self._model_supports_natural_key(field.remote_field.model):
            return None

        related = getattr(obj, field.name, None)
        try:
            return related.natural_key()
        except AttributeError:
            return None

    def _model_supports_natural_key(self, model):
        """Return True if the model defines a natural_key() method."""
        try:
            return callable(model.natural_key)
        except AttributeError:
            return False


class Deserializer:
    """
    Abstract base deserializer class.
    """

    def __init__(self, stream_or_string, **options):
        """
        Init this serializer given a stream or a string
        """
        self.options = options
        if isinstance(stream_or_string, str):
            self.stream = StringIO(stream_or_string)
        else:
            self.stream = stream_or_string

    def __iter__(self):
        return self

    def __next__(self):
        """Iteration interface -- return the next item in the stream"""