Reputation: 170
My goal is to update a Google Sheets document by replacing the content of its first sheet by a table of my own data (that is, a table of instances against attributes of a class). I have attempted to use the module gspread to do so but it hasn't been working out so well: If I run the line
client.open("GoogleSheetName").sheet1.update('A1:R181',Member.display().to_json())
(where Member is my class, and display() is my own class method which simply converts my data to a pandas dataFrame object.), the whole Member.display().to_json()
string is put in the cell A1, as though it is never unpacked and simply left as one string.
If I use the json module and dump my data using json.dumps(Member.display().to_dict())
, I obtain the same problem.
I also attempted to simply change the data to Member.display().to_dict()
, in which case I get an 'Invalid JSON payload received
' error.
It seems like the data may need to be in matrix format for it to work i.e. [[..,..,..][..,..,..]...]
, as that is the only format that has worked properly in my case. I know it works because when I test the API by running
client.open("GoogleSheetName").sheet1.update('A1:B2', [[1, 2], [3, 4]])
each number is put in their own separate cell as wanted. Is that the format I must use?
How may I resolve that issue? It is like my data needs to be sent JSON readable but cannot be a string otherwise it is interpreted as a single argument!
Any help would be very much appreciated.
Upvotes: 2
Views: 998
Reputation: 3321
If Member.display()
is a pandas DataFrame, you can do the following to update the sheet using gspread:
df = Member.display()
ws = client.open("GoogleSheetName").sheet1
ws.update([df.columns.values.tolist()] + df.values.tolist())
Other examples on using gspread with pandas are in the docs.
Sidenote:
Of course, you can use official API as Alberto pointed out. It all depends on your use case. Google Sheets API is a lower-level API. Very powerful but requires a bit more boilerplate code. You can see this if you compare both code examples. It's a tradeoff.
Upvotes: 1
Reputation: 2342
As the official Sheets API says at Method: spreadsheets.values.append Request body
The request body contains an instance of ValueRange.
ValueRange is a JSON that must contain a key named values that must be an array of arrays. I made the following example based on the Python Quickstart to show you how to pass the data you want to your Spreadsheet.
service = discovery.build('sheets', 'v4', credentials=creds)
spreadsheet_id = 'YOUR-SHEETS-ID'
ranges = "A1:A"
value_render_option = "DIMENSION_UNSPECIFIED"
value_input_option = "USER_ENTERED"
df = pd.DataFrame({
'age': [ 3, 29],
'height': [94, 170],
'weight': [31, 115]
})
value_range_body = {
"values": df.to_numpy().tolist(),
"majorDimension": "DIMENSION_UNSPECIFIED"
}
request = service.spreadsheets().values()\
.append(spreadsheetId=spreadsheet_id, range=ranges, valueInputOption=value_input_option, body=value_range_body)
response = request.execute()
print(response)
As you can see, I am using df.to_numpy().tolist()
to convert the pandas dataframe to a NumPy array and then to a normal Python list.
Upvotes: 1