def _ToJSonObj(self, columns_order=None, order_by=()):
    if columns_order is None:
      columns_order = [col["id"] for col in self.__columns]
    col_dict = dict([(col["id"], col) for col in self.__columns])
    col_objs = []
    for col_id in columns_order:
      col_obj = {"id": col_dict[col_id]["id"],
                 "label": col_dict[col_id]["label"],
                 "type": col_dict[col_id]["type"]}
      if col_dict[col_id]["custom_properties"]:
        col_obj["p"] = col_dict[col_id]["custom_properties"]
      col_objs.append(col_obj)
    row_objs = []
    for row, cp in self._PreparedData(order_by):
      cell_objs = []
      for col in columns_order:
        value = self.CoerceValue(row.get(col, None), col_dict[col]["type"])
        if value is None:
          cell_obj = None
        elif isinstance(value, tuple):
          cell_obj = {"v": value[0]}
          if len(value) > 1 and value[1] is not None:
            cell_obj["f"] = value[1]
          if len(value) == 3:
            cell_obj["p"] = value[2]
        else:
          cell_obj = {"v": value}
        cell_objs.append(cell_obj)
      row_obj = {"c": cell_objs}
      if cp:
        row_obj["p"] = cp
      row_objs.append(row_obj)
    json_obj = {"cols": col_objs, "rows": row_objs}
    if self.custom_properties:
      json_obj["p"] = self.custom_properties
    return json_obj