2012-03-01 2 views
3

그래서 내 포스트 그레스 DB에서 나는 다음과 같은 사용자 정의 유형이 있습니다SqlAlchem ​​y의 : PostgreSQL의 사용자 정의 형식의 배열

alter table my_table add column my_keys my_pg_type []; 

I : 더 일을 복잡하게

create type my_pg_type as ( 
    sting_id varchar(32), 
    time_diff interval, 
    multiplier integer 
); 

,이 배열로 사용됩니다 이걸 SQLAlchemy (0.6.4)와 매핑하고 싶습니다 !!

(만능 약에 대한 사과는)

from sqlalchemy.dialects.postgresql import ARRAY 
from sqlalchemy.types import Enum 
from elixir import Entity, Field  

class MyTable(Entity): 
    # -- snip -- 
    my_keys = Field(ARRAY(Enum)) 

내가 '열거'을 알고 위의 올바르지 않습니다. 해당 배열 컬럼에 대한 데이터베이스에서 돌아 오는 값의 예를 들어

, 나는 ARRAY.result_processor(self, dialect, coltype)의 값 아래에 표시했습니다

class ARRAY(sqltypes.MutableType, sqltypes.Concatenable, sqltypes.TypeEngine): 
    # -- snip -- 
    def result_processor(self, dialect, coltype): 
     item_proc = self.item_type.result_processor(dialect, coltype) 
     if item_proc: 
      def convert_item(item): 
       if isinstance(item, list): 
        return [convert_item(child) for child in item] 
       else: 
        return item_proc(item) 
     else: 
      def convert_item(item): 
       if isinstance(item, list): 
        return [convert_item(child) for child in item] 
       else: 
        return item 
     def process(value): 
      if value is None: 
       return value 
      """ 
      # sample value: 
      >>> value 
      '{"(key_1,07:23:00,0)","(key_2,01:00:00,20)"}' 
      """ 
      return [convert_item(item) for item in value] 
     return process 

그래서 위의 process 기능은 잘못이 이미 가정, 문자열을 분할 목록.

지금까지 성공적으로 문자열을 분할하기 위해 ARRAY를 서브 클래 싱했습니다. Enum 대신 자체 유형 (유니 코드 구현)을 작성하여 (string, timedelta, integer) 튜플을 다시 만들려고했으나 많이 실행되었습니다. 특히 interval을 Python timedelta으로 올바르게 변환하는 데 어려움이 있습니다.

이렇게하는 명백한 선례가없는 경우를 대비하여 여기에 게시하고 있습니까?

답변

6

UPDATE는 내가 여기서 무엇을하고 있는지 psycopg2보고 몇 가지 예제 코드를했다

해결을 위해 아래에있는 레시피를 참조하고이 아니라 자신의 영역 내에 - psycopg2는 같은 값을 해석되지 않는다 배열. psycopg2는 SQLA의 ARRAY 유형이 적어도 그렇게 많이 수행되었다고 가정 할 때 ARRAY를 구문 분석 할 수 있어야합니다. 물론 SQLAlchemy의 ARRAY를 해킹 할 수 있습니다.이 ARRIAY는 기본적으로 psycopg2가이 특정 문자열 값을 구문 분석하는 것을 선호하지는 않습니다.

그러나 여기서도 일어나고있는 것은 우리가 timedeltas를 변환하는 psycopg2의 메커니즘에도 미치지 못한다는 것입니다. SQLAlchemy는 일반적으로 걱정할 필요가없는 것입니다. 이 경우 DBAPI의 기능이 제대로 활용되지 않고 psycopg2가 매우 유용한 DBAPI 인 것처럼 느껴집니다.

따라서 psycopg2의 사용자 정의 유형 매커니즘을 http://initd.org/psycopg/docs/extensions.html#database-types-casting-functions 이상으로 사용하는 것이 좋습니다. 당신이 그들의 mailing list 메일하려면

, 여기에 테스트 케이스의 :

import psycopg2 

conn = psycopg2.connect(host="localhost", database="test", user="scott", password="tiger") 
cursor = conn.cursor() 
cursor.execute(""" 
create type my_pg_type as ( 
    string_id varchar(32), 
    time_diff interval, 
    multiplier integer 
) 
""") 

cursor.execute(""" 
    CREATE TABLE my_table (
     data my_pg_type[] 
    ) 
""") 

cursor.execute("insert into my_table (data) " 
      "values (CAST(%(data)s AS my_pg_type[]))", 
      {'data':[("xyz", "'1 day 01:00:00'", 5), ("pqr", "'1 day 01:00:00'", 5)]}) 

cursor.execute("SELECT * from my_table") 
row = cursor.fetchone() 
assert isinstance(row[0], (tuple, list)), repr(row[0]) 

PG의 형식 등록이 글로벌 등록을 지원합니다. 또한 0.6 또는 connect event을 0.7 이상으로 사용하여 pool listener을 SQLAlchemy 내에서 연결 단위로 등록 할 수 있습니다.

UPDATE-https://bitbucket.org/zzzeek/sqlalchemy/issue/3467/array-of-enums-does-not-allow-assigning에 아마 psycopg2이 지원에 내장 된 더 추가 될 때까지 사람들이 지금이 해결 유형을 사용하는 것이 좋습니다거야 인해 :

class ArrayOfEnum(ARRAY): 

    def bind_expression(self, bindvalue): 
     return sa.cast(bindvalue, self) 

    def result_processor(self, dialect, coltype): 
     super_rp = super(ArrayOfEnum, self).result_processor(dialect, coltype) 

     def handle_raw_string(value): 
      inner = re.match(r"^{(.*)}$", value).group(1) 
      return inner.split(",") 

     def process(value): 
      return super_rp(handle_raw_string(value)) 
     return process 
+0

관련 SQLAlchemy의 문제, 나는 포스터가 여기에이 기능을 추가 할 수 psycopg2을 얻을 관리하지 않은 것 같아요 : https://bitbucket.org/zzzeek/sqlalchemy/issue/3467/array -of-enums-does-allow-assign-assigning – zzzeek

3

를 체크 아웃 sqlalchemy_utils 문서 :

CompositeType provides means to interact with 
`PostgreSQL composite types`_. Currently this type features: 

* Easy attribute access to composite type fields 
* Supports SQLAlchemy TypeDecorator types 
* Ability to include composite types as part of PostgreSQL arrays 
* Type creation and dropping 

사용법 :

from collections import OrderedDict 

import sqlalchemy as sa 
from sqlalchemy_utils import Composite, CurrencyType 


class Account(Base): 
    __tablename__ = 'account' 
    id = sa.Column(sa.Integer, primary_key=True) 
    balance = sa.Column(
     CompositeType(
      'money_type', 
      [ 
       sa.Column('currency', CurrencyType), 
       sa.Column('amount', sa.Integer) 
      ] 
     ) 
    ) 
복합 재료의

배열 :

from sqlalchemy_utils import CompositeArray 


class Account(Base): 
    __tablename__ = 'account' 
    id = sa.Column(sa.Integer, primary_key=True) 
    balances = sa.Column(
     CompositeArray(
      CompositeType(
       'money_type', 
       [ 
        sa.Column('currency', CurrencyType), 
        sa.Column('amount', sa.Integer) 
       ] 
      ) 
     ) 
    ) 
+0

좋아 보인다! 나는 지금 시험 할 입장이 아니다. 이것이 언제 추가되었는지, @zzzeek가 추가했는지 알고 싶습니다. – EoghanM

+0

이것은 sqlalchemy를 확장하는 또 다른 프로젝트로 sqlalchemy_utils라고합니다. – pylover

관련 문제