old_contents: from  __future__ import absolute_import
  from functools import partial
  from itertools import chain
  
  from django.db.models import Model
  
  from .comparison import _compare_mapping, register
  from . import compare as base_compare
  
  
  def model_to_dict(instance, exclude, include_not_editable):
      opts = instance._meta
      data = {}
      for f in chain(
          opts.concrete_fields, opts.private_fields, opts.many_to_many
      ):
          if f.name in exclude:
              continue
          if not getattr(f, 'editable', False) and not include_not_editable:
              continue
          data[f.name] = f.value_from_object(instance)
      return data
  
  
  def compare_model(x, y, context):
      """
      Returns an informative string describing the differences between the two
      supplied Django model instances. The way in which this comparison is
      performed can be controlled using the following parameters:
  
      :param ignore_fields:
        A sequence of fields to ignore during comparison, most commonly
        set to ``['id']``. By default, no fields are ignored.
  
      :param non_editable_fields:
        If `True`, then fields with ``editable=False`` will be included in the
        comparison. By default, these fields are ignored.
      """
      ignore_fields = context.get_option('ignore_fields', set())
      non_editable_fields= context.get_option('non_editable_fields', False)
      args = []
      for obj in x, y:
          args.append(model_to_dict(obj, ignore_fields, non_editable_fields))
      args.append(context)
      args.append(x)
      return _compare_mapping(*args)
  
  register(Model, compare_model)
  
  
  compare = partial(base_compare, ignore_eq=True)
  
new_contents: from  __future__ import absolute_import
  from functools import partial
  
  from django.db.models import Model
  
  from .comparison import _compare_mapping, register
  from . import compare as base_compare
  
  
  def instance_fields(instance):
      opts = instance._meta
      for name in (
          'concrete_fields',
          'virtual_fields',
          'private_fields',
          'many_to_many'
      ):
          fields = getattr(opts, name, None)
          if fields:
              for field in fields:
                  yield field
  
  
  def model_to_dict(instance, exclude, include_not_editable):
      data = {}
      for f in instance_fields(instance):
          if f.name in exclude:
              continue
          if not getattr(f, 'editable', False) and not include_not_editable:
              continue
          data[f.name] = f.value_from_object(instance)
      return data
  
  
  def compare_model(x, y, context):
      """
      Returns an informative string describing the differences between the two
      supplied Django model instances. The way in which this comparison is
      performed can be controlled using the following parameters:
  
      :param ignore_fields:
        A sequence of fields to ignore during comparison, most commonly
        set to ``['id']``. By default, no fields are ignored.
  
      :param non_editable_fields:
        If `True`, then fields with ``editable=False`` will be included in the
        comparison. By default, these fields are ignored.
      """
      ignore_fields = context.get_option('ignore_fields', set())
      non_editable_fields= context.get_option('non_editable_fields', False)
      args = []
      for obj in x, y:
          args.append(model_to_dict(obj, ignore_fields, non_editable_fields))
      args.append(context)
      args.append(x)
      return _compare_mapping(*args)
  
  register(Model, compare_model)
  
  
  compare = partial(base_compare, ignore_eq=True)
  
subject: make compatible with django 1.9