def ToCsv(self, columns_order=None, order_by=(), separator=","):
    csv_buffer = six.StringIO()
    writer = csv.writer(csv_buffer, delimiter=separator)
    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])
    def ensure_str(s):
      "Compatibility function. Ensures using of str rather than unicode."
      if isinstance(s, str):
        return s
      return s.encode("utf-8")
    writer.writerow([ensure_str(col_dict[col]["label"])
                     for col in columns_order])
    for row, unused_cp in self._PreparedData(order_by):
      cells_list = []
      for col in columns_order:
        value = ""
        if col in row and row[col] is not None:
          value = self.CoerceValue(row[col], col_dict[col]["type"])
        if isinstance(value, tuple):
          if col_dict[col]["type"] in ["date", "datetime", "timeofday"]:
            cells_list.append(ensure_str(self.ToString(value[1])))
          else:
            cells_list.append(ensure_str(self.ToString(value[0])))
        else:
          cells_list.append(ensure_str(self.ToString(value)))
      writer.writerow(cells_list)
    return csv_buffer.getvalue()