Trying to create a dictionary from a mysql database using two columns and then assign it a variable keep getting the traceback AttributeError: 'tuple' object has no attribute 'name'.
cursor = conn.cursor()
cursor.execute("select server_id, name from servers")
dict = {}
for row in cursor:
dict[row.server_id] = row.name
print(dict)
Rows are tuples, not objects with named attributes per column. In your case, name is the value at index 1, the server_id the value at index 0:
d = {}
for row in cursor:
d[row[0]] = row[1]
print(d)
You could make this easier on yourself by using tuple assignments:
d = {}
for server_id, name in cursor:
d[server_id] = name
print(d)
However, because you want to use the first element as the key, and the second as the value, you could make this even simpler and just pass the cursor directly to a dict() call:
d = dict(cursor)
This pulls in each (server_id, name) tuple and turns it into a key and value pair in a new dictionary.
Note that I deliberately used the name d for the dictionary in the above examples. Had I used dict instead, then we couldn't use dict(cursor) anymore!
row in your case is tuple (server_id, name), that's why calling row.name won't work - tuples don't support named attributes. Try row[0] and row[1] instead or unpack tuple:
d = {}
for row in cursor:
server_id, name = row
d[server_id] = name
print(d)
Related
I need to take this dictionary {'1': 9, '2': 5} (or one like it), and replace all the keys with their respective names from a database.
I was able to get the appropriate names from the database and put them in a list as dictionary entries. But now I'm in a bit of a pickle - the first dictionary needs to get their keys replaced with the keys in the names list I created from the database (which keeps giving me errors). The only other solution that I can personally think of is to find a way to get the database names and put them directly into the dictionary as opposed to a blank list, but I can't figure out how to do that using loops.
empty_list = [] **# stores it as [{"name": name1}, {"name":, name2},...]**
for x in range(0, len(dict_key_array)):
data = {
"itm_num": dict_key_array[x]
}
mysql = connectToMySQL("app_database")
query = "SELECT name, price FROM items WHERE items.id = %(itm_num)s;"
pre_empty_list = mysql.query_db(query, data)
empty_list.append(pre_empty_list)
I've tried this so far in order to get the names to take their respective places in the original dictionary:
for k in order_data.keys(): **# go through each key of dictionary**
for x in range(0, len(order_data)): **# create a counter(? I think this would lead to duplicates, but I don't know how to avoid this)**
neym = empty_list[x]['name'] **# template debugger says: "TypeError: list indices must be integers or slices, not str"**
order_data[neym] = order_data[k]
del order_data[k]
I need to get the original dictionary of {'1': 9, '2': 5} (or one like it since this is based on an orders page and different orders will have different keys and values) to show up like {'pasta': 9, 'soda': 5} where 'pasta' and 'soda' are the names found in the database.
I'm not sure if all is correct but it could be
# --- get names ---
mysql = connectToMySQL("app_database")
query = "SELECT name, price FROM items WHERE items.id = %(itm_num)s;"
empty_list = [] # **stores it as [{"name": name1}, {"name":, name2},...]**
for item in dict_key_array:
result = mysql.query_db(query, {"itm_num": item})
empty_list.append(result)
# --- convert keys in order ---
order_data = {'1': 9, '2': 5}
for key in order_data:
index = int(key)-1 # convert str to int # key has value 1,2,3,... but list use 0,1,2,...
name = empty_list[index]['name']
order_data[name] = order_data.pop(key)
#del order_data[key] # .pop() will remove it
But probably you should keep name with itm_num as dict {itm_num1: {'name": name1}, itm_num2: {"name": name2} } or even {itm_num1: name1, itm_num2: name2}
# --- get names ---
mysql = connectToMySQL("app_database")
query = "SELECT name, price FROM items WHERE items.id = %(itm_num)s;"
empty_dict = dict() # **stores it as {itm_num1: {'name": name1}, itm_num2: {"name": name2} }**
for item_num in dict_key_array:
empty_dict[item_num] = mysql.query_db(query, {"itm_num": item_num})
# --- convert keys in order ---
order_data = {'1': 9, '2': 5}
for key in order_data:
name = empty_dict[key]['name']
order_data[name] = order_data.pop(key)
#del order_data[key] # .pop() will remove it
Maybe you could even get it in one query "SELECT id, name, price FROM items"
result = mysql.query_db("SELECT id, name, price FROM items")
for row in result:
empty_dict[row['id']] = row
but it will get all rows for database. But you can get it from database once and use empty_dict all the time with different orders.
I solved it:
empty_list = []
for x in range(0, len(dict_key_array), 2):
data6 = {
"itm_num": int(dict_key_array[x])
}
mysql = connectToMySQL("app_database")
query = "SELECT name, price FROM items WHERE items.id = %(itm_num)s;"
pre_empty_list = mysql.query_db(query, data)
empty_list.append(pre_empty_list[0]['name'])
new_dict = {}
counter = 0
while counter < len(dict_val_array):
for name in empty_list:
new_dict[name] = dict_val_array[counter]
counter+=1
session['new_dict'] = new_dict
Comments: I already had the dictionary of order items along with their quantities. I looped through that and put all the keys into a list, and put all the values into another list (dict_key_array and dict_val_array). What really changed this time around, however, was that instead of saving all my query results as a list, I specified which parts of my query results should be saved in the list, which is why I have above pre_empty_list[0]['name'], that would put the name alone in the list, and after this I used a while loop as a counter so that I enter each name in the list as a key and assign it the value found int he values list (dict_val_array).
Im using psycopg2 to access postgres database using the below query. In order to return a dictionary from the executed query, im using DictCursor in my cursor but still my output is a list and not a dictonary.
Here is the program and output below.
import psycopg2.extras
try:
conn = psycopg2.connect("user='postgres' host='localhost' password='postgres'",
)
except:
print "I am unable to connect to the database"
cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
cur.execute("""SELECT datname from pg_database""")
rows = cur.fetchall()
print "\nShow me the databases:\n"
print rows
Output:-
[['template1'], ['template0'], ['postgres'], ['iip'], ['test'], ['test_postgres'], ['testdb']]
It looks like a list, smells like a list, but it's a DictRow.
rows = cur.fetchall()
for row in rows :
print(type(row))
#>>> <class 'psycopg2.extras.DictRow'>
This means that you can still use the column names as keys to access the data :
rows = cur.fetchall()
print([row['datname'] for row in rows])
This class inherits directly from the builtinlist and add all the needed methods to implement a dictionary logic, but it doesn't change the representation __repr__ or __str__, so the output is the same as a list.
class DictRow(list):
"""A row object that allow by-column-name access to data."""
fetchall() packs all the queried rows in a list without specifying the exact type.
Btw, maybe you are looking for this kind of cursor : RealDictCursor ?
For those who came where because they really like the easy reference of the dictionary for column:value record representation, the answer by PRMoureu which notes that the DictRow has all the usual dictionary logic means that you can iterate over the DictRow with .items() and get the key:value pairs.
rows = cur.fetchall()
row_dict = [{k:v for k, v in record.items()} for record in rows]
Will turn your list of DictRow records into a list of dict records.
I've created a nested dictionary calling values from a table, and I need to update the attribute table for a feature class using that data. I have it working with two hard-coded fields as a test, but I need to figure out how to automate getting the length of featFields and using that to indicate the index position for each field to be updated. So, instead of hard-coding row[1], row[2], etc. and 'LOCDESC' and 'RIMELEV', I'd be using a variable to step through index positions for each one.
I am working in Python. End goal is a toolbox for use in ArcMap 10.2 or 10.3.
import arcpy
arcpy.env.workspace = r"C:/SARP10/MACP_Tool"
#Define fields to update and the field to use as join field
Table = "Test2.csv"
Input = "Test.gdb/MHs"
csvFields = ['Location_Details', 'Elevation']
featFields = ['LOCDESC', 'RIMELEV']
csvKey = "Manhole_Number"
featKey = "FACILITYID"
csvFields.insert(0, csvKey)
featFields.insert(0, featKey)
print csvFields
#Create dictionary to store values from the update table
UpdateDict = {}
#Iterates through the values in the table and stores them in UpdateDict
with arcpy.da.SearchCursor(Table, csvFields) as cursor:
for row in cursor:
UpdateDict[row[0]] = dict(zip(featFields[1:], row[1:]))
print UpdateDict
MHNum = len(UpdateDict) # gets # of MHs to be updated
MHKeys = UpdateDict.keys() # gets key values, i.e. MH numbers
print "You are updating fields for the following {} manholes: {}".format(MHNum, MHKeys)
#Iterates through feature class attribute table and updates desired attributes
with arcpy.da.UpdateCursor(Input, featFields) as cursor:
i = 0
z = 0
for row in cursor:
i += 1
for f in UpdateDict.keys():
if f == row[0]:
row[1] = UpdateDict.values()[z]['LOCDESC']#uses counter and subdict key to call correct value
row[2] = UpdateDict.values()[z]['RIMELEV']#uses counter and subdict key to call correct value
cursor.updateRow(row)
z +=1 #counter keeps track of rows and provides index location for dictionary
print "Updating {} of {} manholes in this submittal: {}.".format(z, MHNum, f)
else:
pass
print "Updated {} of {} rows.".format(MHNum, i)
print "Script completed."
Since the (currently hard-coded) iteration of row[n] steps through the values of featFields, you can set up an for loop that iterates through them both, something like:
if f == row[0]:
# loop set by length of featFields list
for j in range(0, len(featFields) - 1):
row[j + 1] = UpdateDict.values()[z][featFields[j]]
cursor.updateRow(row)
# etc.
Note the "offset" -- row[1] should be using featFields[0] and so on -- that needs to be accounted for.
The problem was with accessing the right fields in the data dictionary. Final code accesses a list of outer keys and a list of inner key: value pairs with a variable (z) set to keep the index number equal in both lists. Thanks for your help, #Erica!
Here's what works:
import arcpy
arcpy.env.workspace = r"C:/SARP10/MACP_Tool"
#Defines fields to update and the field to use as join field
Table = "Test2.csv"
Input = "Test.gdb/MHs"
csvFields = ['Location_Details', 'Elevation', 'Rim_to_Invert', 'Rim_to_Grade', 'Cover_Size', 'Wall_Material', 'Wall_Diam', 'Wall_Lining_Interior', 'Photo2_Link', 'MH_InspectReportLink'] #update table fields
featFields = ['LOCDESC', 'RIMELEV', 'RIMTOINVERT', 'RIMTOGRADE','COVERSIZE','WALLMAT','DIAMETER','LINERTYPE','HYPERLINK_PHOTO2','HYPERLINK_RPT']#fc field names
csvKey = "Manhole_Number"
featKey = "FACILITYID"
csvFields.insert(0, csvKey)
featFields.insert(0, featKey)
print "Your table contains the following fields to be updated: {}\n".format(str(csvFields))
#Process: Create dictionary to store values from the update table, iterate through values and store in UpdateDict
UpdateDict = {}
with arcpy.da.SearchCursor(Table, csvFields) as cursor:
for row in cursor:
UpdateDict[row[0]] = dict(zip(featFields[1:], row[1:]))
## debug print "You have created update dictionary 'UpdateDict': \n{}\n\n".format(UpdateDict)
MHNum = len(UpdateDict) # gets # of MHs to be updatedMHKeys = sorted(UpdateDict.keys()) # gets key values, i.e. MH numbers
MHKeys = UpdateDict.keys() #calls outer keys (MH numbers, which are join values) into a list of keys
MHVals = UpdateDict.values()#calls inner nested key:value pairs to a list
##debug print "Dictionary keys: {}\n\n Dictionary values: {}\n\n".format(str(MHKeys),str(MHVals))
print "You are updating fields for the following {} manholes: {}".format(MHNum, str(MHKeys))
#Process: Iterates through feature class attribute table and updates desired attributes
with arcpy.da.UpdateCursor(Input, featFields) as curs:
i = 0 #attribute table row counter
for row in curs:
i += 1
for f in MHKeys:
if f == row[0]:
z = MHKeys.index(f)#get index location in MHKeys
for y in range(0,len(featFields)-1):
row[y+1] = MHVals[z][featFields[y+1]]#use z to pull corresponding value in MHVals to correct key in MHKeys
print "Current MH: {} \nUpdating Values: {} \n\n".format(f, UpdateDict.values()[z])
curs.updateRow(row)
else:
pass
print "Updated {} of {} rows.".format(MHNum, i)
print "Script completed."
We have a PostGres Database which I am accessing with Python. When Querying for a column with type bigint I get back a dictionary with in the following format:
[[263778L], [30188L], [97L], [12215192L], [702819L], [1301581L], [11101568L], [4712L], [1107866L]]
I need to add these values up together, but I cannot access them as integers.
Fails:
...
cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
cur.execute("SELECT column1 FROM relation1
rec = cur.fetchall()
for row in rec:
print(re.findall('\d+', row))
Python is returning:
TypeError: expected string or buffer
How to achieve what I want?
This is a list of lists:
[[263778L], [30188L], [97L], [12215192L], [702819L], [1301581L], [11101568L], [4712L], [1107866L]]
not a dictionary. To print each value:
for row in rec:
print(row[0])
Is there any way to get the column names from the pymssql results? If i specify as_dict=True I get back a dictionary, which does contain all the column headers, but since it is a dictionary they are not ordered.
pymssql claims to support the Python DB-API, so you should be able to get the .description attribute from your cursor object.
.description
This read-only attribute is a sequence of 7-item
sequences.
Each of these sequences contains information describing
one result column:
(name,
type_code,
display_size,
internal_size,
precision,
scale,
null_ok)
So, the first item in each of the "inner" sequences is the name for each column.
You can create a list of ordered column names using list comprehension on the cursor description attribute:
column_names = [item[0] for item in cursor.description]
To get the column names on a single comma separated line.
colNames = ""
for i in range(len(cursor.description)):
desc = cursor.description[i]
if i == 0:
colNames = str(desc[0])
else:
colNames += ',' + str(desc[0])
print colNames
Alternatively, pass the column names to a list and use .join to get them as string.
colNameList = []
for i in range(len(cursor.description)):
desc = cursor.description[i]
colNameList.append(desc[0])
colNames = ','.join(colNameList)
print colNames
It's a basic solution and need optimizing but the below example returns both column header and column value in a list.
import pymssql
def return_mssql_dict(sql):
try:
con = pymssql.connect(server, user, password, database_name)
cur = con.cursor()
cur.execute(sql)
def return_dict_pair(row_item):
return_dict = {}
for column_name, row in zip(cur.description, row_item):
return_dict[column_name[0]] = row
return return_dict
return_list = []
for row in cur:
row_item = return_dict_pair(row)
return_list.append(row_item)
con.close()
return return_list
except Exception, e:
print '%s' % (e)