2011-07-18 34 views
36

Tôi chưa từng làm việc với psycopg2 trước đây nhưng tôi đang cố gắng thay đổi nhà máy con trỏ thành DictCursor để fetchall hoặc fetchone sẽ trả lại từ điển thay vì danh sách.DictCursor dường như không hoạt động dưới psycopg2

Tôi đã tạo tập lệnh thử nghiệm để làm mọi thứ đơn giản và chỉ kiểm tra chức năng này. Đây là chút mã của tôi mà tôi cảm thấy sẽ hoạt động

import psycopg2 
import psycopg2.extras 

conn = psycopg2.connect("dbname=%s user=%s password=%s" % (DATABASE, USERNAME, PASSWORD)) 

cur = conn.cursor(cursor_factory = psycopg2.extras.DictCursor) 
cur.execute("SELECT * from review") 

res = cur.fetchall() 

print type(res) 
print res 

Biến res luôn là danh sách chứ không phải từ điển như tôi mong đợi.

Giải pháp khắc phục hiện tại mà tôi đã triển khai là sử dụng chức năng này để tạo từ điển và chạy từng hàng được trả về bằng fetchall thông qua nó.

def build_dict(cursor, row): 
    x = {} 
    for key,col in enumerate(cursor.description): 
     x[col[0]] = row[key] 
    return d 

Python là phiên bản 2.6.7 và psycopg2 là phiên bản 2.4.2.

Trả lời

20
res = cur.fetchall() 

làm res danh sách psycopg2.extras.DictRow s.


Ngoài ra, thay vì gọi cur.fetchall bạn có thể tận dụng thực tế là cur là một iterable:

cur.execute("SELECT * from review") 
for row in cur: 
    print(row['column_name']) 

và do đó bạn sẽ có thể truy cập dữ liệu với dict -like cú pháp.

+0

Cảm ơn, tôi nghĩ rằng bạn đang phát hiện ra "giống như dict". Đó là một danh sách nhưng hoạt động như một từ điển. Điều đó có vẻ như một quyết định thiết kế kỳ lạ nhưng ít nhất nó đang hoạt động ngay bây giờ. Cảm ơn một lần nữa. – Jim

+12

@Seth: Nếu bạn muốn có một từ điển thực, sử dụng aptly tên là 'RealDictCursor'. –

+0

@Seth: một từ điển không có thứ tự để bạn không thể sử dụng nó như một bộ dữ liệu nữa, cột đầu tiên trong truy vấn sẽ không còn là 'hàng [0]' nữa mà là một cái gì đó tùy ý. Vì vậy, có một số công đức cho nó :) – Wolph

64

Sử dụng RealDictCursor:

cur = conn.cursor(cursor_factory = psycopg2.extras.RealDictCursor) 
cur.execute("SELECT * from review") 
res = cur.fetchall()  

này cung cấp cho bạn một danh sách với hàng như từ điển python thực thay vì "danh sách psycopg2 tiên tiến".

+1

Cảm ơn. Nó hoạt động tốt. – ibi0tux

+1

Có điều này hoạt động .. Nộp như lỗi trong chai-plugin https://github.com/raisoblast/bottle-pgsql/issues/2 – PedroMorgan

0

Ngoài việc sử dụng tính năng RealDictCursor, bạn cũng có thể yêu cầu tất cả các cột (sử dụng ký hiệu * sau khi chọn), như được thực hiện trong câu trả lời.

Tôi không quan tâm đến một số cột của kết quả, vì chúng có giá trị đã biết đã được sử dụng trong điều kiện WHERE. Nhưng biến thể SELECT (..., ..., ..., ...) FROM ... WHERE ... không cung cấp cho tôi từ điển.

Trân trọng! Harley

+0

Rời khỏi dấu ngoặc đơn và truy vấn của bạn hoạt động: 'SELECT ..., ..., ..., ... TỪ ... Ở ĐÂU ... '. –

5

Một giải pháp khác là sử dụng Named Tuple Cursor vì Con trỏ thật sẽ phá vỡ bất kỳ truy vấn nào sử dụng số nguyên như được giải thích trong tài liệu của nó.

Với Cursors tuple đặt tên, bạn có thể truy cập chúng với dấu chấm cú pháp như sau:

import psycopg2 
import psycopg2.extras 
cur = conn.cursor(cursor_factory = psycopg2.extras.NamedTupleCursor) 
cur.execute("SELECT * from review") 
res = cur.fetchone() 
res.key1 
res.key2 

Điều này sẽ giúp mọi thứ gọn gàng và sẽ không phá vỡ bất cứ điều gì như xa như tôi biết.

+0

Ngoài ra, toàn bộ kết quả có thể được chuyển đổi thành một danh sách các dicts như thế này: '[row._asdict() cho hàng trong cur]' – GetFree

3

Trong khi đây là một câu hỏi cũ, nó vẫn đi lên trong google vì vậy tôi nghĩ rằng tôi sẽ thêm mã của tôi để điều này cho bất cứ ai khác đến từ lớn G.

Đối với tôi, tôi có nhiều hàng mà tôi sẽ muốn quay lại từ điển và lý tưởng là không muốn sử dụng vòng lặp hoặc tương tự để đặt khóa từ trường trong cơ sở dữ liệu ..

Vì vậy, sử dụng dict comprehension syntax tôi có thể làm như sau.

Bảng hàng vào từ điển


pgCursor = Conn.cursor(cursor_factory = psycopg2.extras.RealDictCursor) 
pgCursor.execute("SELECT * FROM tablename;",([])) 
dictRows = {n['id']: n for n in pgCursor} 

Chức năng & Calling Nó

#NOTE this is using a class object hence the self param 
def DBTableToDictByID(self, squery): 
    self.Pointer.execute(squery,([])) 
    return {n['id']: n for n in self.Pointer} 

dictRows = self.DBTableToDictByID("SELECT * FROM tablename;") 

Trong khi điều này được sử dụng cho một x trong y loop, pythonic của nó như xa như tôi có thể nói .... Hy vọng rằng điều này sẽ giúp đỡ một số ra khỏi đó.

0

Vì vậy, để thực hiện công việc này giống như phiên bản mysql của con trỏ Từ điển, bạn sẽ phải bọc nó trong một hàm hoặc mã khác. Tôi sẽ đi trên các diễn đàn và đề xuất điều này cho họ để triển khai trong tương lai mã của họ để trả về một từ điển khi gọi fetchall() được sử dụng với Con trỏ Từ điển. Dưới đây là một số mã mẫu mà bạn có thể sử dụng để sửa lỗi cho nó:

cursor.execute(query) 
# Python 2.7 and beyond with dictionary comprehension 
results = [{key:value for key,value in row.iteritems()} for row in cursor] 
# Python 2.6 and before 
# results = [dict((key,value) for key,value in row.iteritems()) for row in cursor] 

Mã này làm cho định dạng giống như phiên bản MySQL của con trỏ từ điển sử dụng fetchall(). Không chắc chắn lý do tại sao họ thực hiện nó một cách khác nhau, nhưng điều này sẽ giúp bạn có được cùng một đầu ra của một từ điển python thực tế chứ không phải là một danh sách trong trường hợp fetchall().

Các vấn đề liên quan