psycopg2 mapping Python : “list of dicts” to Postgres : “array of composite type” for an INSERT statement

我怕爱的太早我们不能终老 提交于 2019-12-01 20:18:01

问题


Postgres version : 9.1.x.

Say I have the following Schema:

DROP TABLE IF EXISTS posts CASCADE;
DROP TYPE IF EXISTS quotes CASCADE;

CREATE TYPE quotes AS
(
  text  CHARACTER VARYING,
  is_direct CHARACTER VARYING
);

CREATE TABLE posts
(
    body  CHARACTER VARYING,
    q     quotes[]
);

And I wish to perform the following insert, shown in SQL, but from Python Psycopg2.

insert into posts(body,q) VALUES('ninjas rock',ARRAY[ ROW('I AGREE',True)::quotes, ROW('I DISAGREE',FALSE)::quotes ]);

What is the syntax to achieve this (without loops and such). I am sure it is possible since the documentation says "Changed in version 2.4.3: added support for array of composite types". The documentation only shows examples of SELECT statements.

Note: I have a list of dicts in my client code that conceptually map to the psuedo-schema above.

edit:

Hmm I must have missed this from the documentation : "Adaptation from Python tuples to composite types is automatic instead and requires no adapter registration.". Now to figure out the array part.

edit 2:

psycopg2's %s placeholder should work when the data type passed is list(tuple) or list(dict). Gotta test it out :D

edit3: Ok almost there, dicts dont work in this scenario, lists do, and tuples do. However, I need to cast the tuple string representation into the composite record type.

This :

quote_1 = ("monkeys rock", "False")
quote_2 = ("donkeys rock",  "True")
q_list = [ quote_1, quote_2]
print cur.mogrify("insert into posts VALUES(%s,%s)", ("animals are good", q_list))

Creates the following string:

insert into posts VALUES('animals are good',ARRAY[('monkeys rock', 'false'), ('donkeys rock', 'true')])

Which produces the following error :

psycopg2.ProgrammingError: column "q" is of type quotes[] but expression is of type record[]

回答1:


Extending your efforts just a tiny bit, how about:

quote_1 = ("monkeys rock", "False")
quote_2 = ("donkeys rock",  "True")
q_list = [ quote_1, quote_2]
print cur.mogrify("insert into posts VALUES(%s,%s::quotes[])", 
                  ("animals are good", q_list))
#
#                 added explicit cast to quotes[]->^^^^^^^^

Explanation:

If you run:

insert into posts 
VALUES('animals are good', ARRAY[
    ('monkeys rock', 'false'),
    ('donkeys rock', 'true')
]);

directly in psql you'll get:

regress=# insert into posts 
regress-# VALUES('animals are good',ARRAY[
regress-#             ('monkeys rock', 'false'),
regress-#             ('donkeys rock', 'true')
regress-#  ]);
ERROR:  column "q" is of type quotes[] but expression is of type record[]
LINE 1: insert into posts VALUES('animals are good',ARRAY[('monkeys ...
                                                    ^
HINT:  You will need to rewrite or cast the expression.

Sure enough, telling Pg that your anonymous array is of type quotes[] does the trick:

regress=# insert into posts 
regress-# VALUES('animals are good',ARRAY[
regress-#           ('monkeys rock', 'false'),
regress-#           ('donkeys rock', 'true')
regress-# ]::quotes[]);
INSERT 0 1

regress=# select * from posts;
       body       |                           q                            
------------------+--------------------------------------------------------
 animals are good | {"(\"monkeys rock\",false)","(\"donkeys rock\",true)"}
(1 row)


来源:https://stackoverflow.com/questions/11957925/psycopg2-mapping-python-list-of-dicts-to-postgres-array-of-composite-type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!