2012-03-01 52 views
3

だから私のPostgresのDBに、私は次のカスタムタイプがあります。さらに物事を複雑にするSQLAlchemyの:PostgreSQLのカスタム型の配列

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

を、これは配列として使用されている:

alter table my_table add column my_keys my_pg_type []; 

Iこれを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)) 

私は '列挙型' は上記で間違っている知っています。そのアレイの列に戻って、データベースから来る値の例えば

、Iは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)タプルを再作成するために独自の型(Unicodeを実装)を作成しようとしましたが、特にintervalをPython timedeltaに適切に変換することが困難です。

これを行うための明白な先例がない場合に備えて、ここに投稿していますか?

答えて

6

UPDATE私はここでやっていることpsycopg2見るためにいくつかのサンプルコードを後処理し、これはうまく自分の領域内での回避策

のために下にあるレシピを参照してください - psycopg2はとして値を解釈されていません全く配列。 psycopg2は、SQLAのARRAYタイプが少なくともそれほど多く行われていることを前提としているため、ARRAYを解析する必要があります。もちろん、SQLAlchemyのARRAYをハックすることもできます。これは、基本的には、この特定の文字列値を解析してpsycopg2が私たちに戻ってくるものを好む意味ではありません。

でも、ここでも起こっているのは、timeceltを変換するpsycopg2のメカニックにさえいないということです.SQLAlchemyでは、通常は気にする必要がないことです。この場合、私はDBAPIの機能が十分に活用されていないと感じ、psycopg2は非常に有能なDBAPIです。

私はhttp://initd.org/psycopg/docs/extensions.html#database-types-casting-functionsのpsycopg2のカスタムタイプのメカニックで作業することをお勧めします。

あなたが彼らの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のタイプの登録はグローバルな登録をサポートしています。 SQLAlchemy内の接続ごとにタイプを登録するには、pool listener(0.6)またはconnect event(0.7)を使用します。

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-not-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

関連する問題