我想在SQLAlchemy中創建一個不區分大小寫的唯一約束,它可以同時用於Postgres和SQLite。SQLAlchemy中的編譯擴展:索引中使用的函數
在Postgres裏,可以實現:
- SQL:
CREATE UNIQUE INDEX my_index ON my_table (lower(my_field));
- SQLAlchemy的:
Index('my_index', func.lower(my_field), unique=True)
在SQLite的它正在使用來實現:
- SQL:
CREATE UNIQUE INDEX my_index ON my_table (my_field COLLATE NOCASE);
- SQLAlchemy的:
Index('my_index', collate(my_field, 'nocase'), unique=True)
所以我想子類FunctionElement
爲了創建自己的功能樣結構,這將彙編要麼my_field COLLATE NOCASE
或lower(my_field)
根據的DBMS。我試圖按照the guide to compilation extension,但我得到一個錯誤(請參閱下面的回溯),我可以通過SQLAlchemy源代碼遵循,但我不明白。我嘗試了子類別的其他東西,如ColumnElement
,ColumnClause
,ClauseElement
,但我收到類似的錯誤。
這裏是重現錯誤的代碼。我使用SQLAlchemy的0.8.2版本。
from sqlalchemy import create_engine, Column, String, Integer
from sqlalchemy.types import TypeDecorator, VARCHAR
from sqlalchemy import func, Index, collate
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.expression import (
# Not sure which one to subclass
FunctionElement, ColumnElement, ColumnClause, ClauseElement
)
engine = create_engine('sqlite:///:memory:', echo=True)
Base = declarative_base()
class CaseInsensitive(FunctionElement):
name = 'CaseInsensitive'
type = VARCHAR()
@compiles(CaseInsensitive, 'sqlite')
def case_insensitive_sqlite(element, compiler, **kw):
arg1, = list(element.clauses)
return collate(compiler.process(arg1), 'nocase')
@compiles(CaseInsensitive, 'postgresql')
def case_insensitive_postgresql(element, compiler, **kw):
arg1, = list(element.clauses)
return func.lower(compiler.process(arg1))
class MyTable(Base):
__tablename__ = 'my_table'
id = Column(Integer, primary_key=True)
my_field = Column(String)
__table_args__ = (
Index('idx', CaseInsensitive(my_field), unique=True),
)
Traceback (most recent call last):
File "tmp.py", line 33, in <module>
class MyTable(Base):
File "/Users/vladimir/git/wb/lib/python2.7/site-packages/sqlalchemy/ext/declarative/api.py", line 50, in __init__
_as_declarative(cls, classname, cls.__dict__)
File "/Users/vladimir/git/wb/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 222, in _as_declarative
**table_kw)
File "/Users/vladimir/git/wb/lib/python2.7/site-packages/sqlalchemy/schema.py", line 332, in __new__
table._init(name, metadata, *args, **kw)
File "/Users/vladimir/git/wb/lib/python2.7/site-packages/sqlalchemy/schema.py", line 400, in _init
self._init_items(*args)
File "/Users/vladimir/git/wb/lib/python2.7/site-packages/sqlalchemy/schema.py", line 65, in _init_items
item._set_parent_with_dispatch(self)
File "/Users/vladimir/git/wb/lib/python2.7/site-packages/sqlalchemy/events.py", line 236, in _set_parent_with_dispatch
self._set_parent(parent)
File "/Users/vladimir/git/wb/lib/python2.7/site-packages/sqlalchemy/schema.py", line 2421, in _set_parent
ColumnCollectionMixin._set_parent(self, table)
File "/Users/vladimir/git/wb/lib/python2.7/site-packages/sqlalchemy/schema.py", line 2035, in _set_parent
self.columns.add(col)
File "/Users/vladimir/git/wb/lib/python2.7/site-packages/sqlalchemy/sql/expression.py", line 2477, in add
self[column.key] = column
File "/Users/vladimir/git/wb/lib/python2.7/site-packages/sqlalchemy/sql/expression.py", line 2296, in __getattr__
key)
AttributeError: Neither 'CaseInsensitive' object nor 'Comparator' object has an attribute 'key'
雖然這並不關心的問題,直接,我還沒有看到「表ARGS」之前建造。對於其他人的幫助,如果您想知道[「__table args__」](http://docs.sqlalchemy.org/en/rel_0_7/orm/extensions/declarative.html#declarative-table-args),請點擊此處鏈接。 – Soferio