docs: def Deserializer(stream_or_string, **options):
      """
      Deserialize a stream or string of JSON data.
      """
  
      geometry_field = options.get("geometry_field", "geom")
  
      def FeatureToPython(dictobj):
          properties = dictobj['properties']
          model_name = options.get("model_name") or properties.pop('model')
          # Deserialize concrete fields only (bypass dynamic properties)
          model = _get_model(model_name)
          field_names = [f.name for f in model._meta.fields]
          fields = {}
          for k, v in iteritems(properties):
              if k in field_names:
                  fields[k] = v
          obj = {
              "model": model_name,
              "pk": dictobj.get('id') or properties.get('id'),
              "fields": fields
          }
          if isinstance(model._meta.get_field(geometry_field), GeoJSONField):
              obj['fields'][geometry_field] = dictobj['geometry']
          else:
              shape = GEOSGeometry(json.dumps(dictobj['geometry']))
              obj['fields'][geometry_field] = shape.wkt
          return obj
  
      if isinstance(stream_or_string, string_types):
          stream = StringIO(stream_or_string)
      else:
          stream = stream_or_string
      try:
          collection = json.load(stream)
          objects = [FeatureToPython(f) for f in collection['features']]
          for obj in PythonDeserializer(objects, **options):
              yield obj
      except GeneratorExit:
          raise
      except Exception as e:
          # Map to deserializer error
          raise DeserializationError(repr(e))