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

Code before:
        related object's natural key; otherwise it falls back to the PK.
        """
        if not self.use_natural_foreign_keys:
            return None

        if not self._model_supports_natural_key(field.remote_field.model):
            return None

        related = getattr(obj, field.name, None)
        return self._resolve_natural_key(related)

    def _resolve_natural_key(self, obj):
        """
        Return a natural key tuple for the given object when available.
        """
        if not (obj and callable(getattr(obj, "natural_key", None))):
            return None

        natural_key_value = obj.natural_key()
        if self._is_natural_key_opt_out(natural_key_value):
            return None

        return natural_key_value

    def _is_natural_key_opt_out(self, natural_key_value):
        return not natural_key_value or not isinstance(natural_key_value, tuple)

    def _model_supports_natural_key(self, model):
        """Return True if the model class exposes a callable natural_key()."""
        natural_key = getattr(model, "natural_key", None)
        return callable(natural_key)


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


Review comment (refactor):
```suggestion
        return not natural_key_value
```

Lists worked before via duck-typing, so let's make sure we don't remove support.

Given that, you probably don't need this helper.

Code after:
        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"""
        raise NotImplementedError(
            "subclasses of Deserializer must provide a __next__() method"
        )


class DeserializedObject:
    """
    A deserialized model.

    Basically a container for holding the pre-saved deserialized data along
    with the many-to-many data saved with the object.

    Call ``save()`` to save the object (with the many-to-many data) to the
    database; call ``save(save_m2m=False)`` to save just the object fields
    (and not touch the many-to-many stuff.)
    """

    def __init__(self, obj, m2m_data=None, deferred_fields=None):