1. ホーム
  2. パイソン

[解決済み】sqlalchemy 複数のカラムにまたがる一意性

2022-04-07 16:52:36

質問

例えば、場所を表すクラスがあるとします。ロケーションは顧客に属しています。ロケーションは、ユニコードの10文字コードで識別されます。ロケーションコード("location code")は、特定の顧客のためのロケーションの中でユニークでなければならない。

The two below fields in combination should be unique
customer_id = Column(Integer,ForeignKey('customers.customer_id')
location_code = Column(Unicode(10))

つまり、2人の顧客、顧客 "123" と顧客 "456" がいる場合です。両者とも "main"というロケーションを持つことはできますが、mainというロケーションを2つ持つことはできないのです。

ビジネスロジックで処理することは可能ですが、sqlalchemyで簡単に要件を追加する方法がないかを確認したいのです。unique=True オプションは特定のフィールドに適用されたときのみ機能するようで、テーブル全体がすべてのロケーションに対してユニークなコードのみを持つことになります。

解決方法は?

を抽出します。 ドキュメント Column :

ユニーク - True の場合、このカラムが一意であることを示します。 制約がある場合、または インデックス もTrueの場合、インデックス はユニークフラグ付きで作成する必要があります。複数のカラムを指定するには 制約/インデックスを指定したり、明示的な名前を指定するには ユニーク制約 または インデックス を明示的に構築します。

これらはテーブルに属し、マップされたクラスには属さないので、テーブルの定義の中でそれらを宣言します。 __table_args__ :

# version1: table definition
mytable = Table('mytable', meta,
    # ...
    Column('customer_id', Integer, ForeignKey('customers.customer_id')),
    Column('location_code', Unicode(10)),

    UniqueConstraint('customer_id', 'location_code', name='uix_1')
    )
# or the index, which will ensure uniqueness as well
Index('myindex', mytable.c.customer_id, mytable.c.location_code, unique=True)


# version2: declarative
class Location(Base):
    __tablename__ = 'locations'
    id = Column(Integer, primary_key = True)
    customer_id = Column(Integer, ForeignKey('customers.customer_id'), nullable=False)
    location_code = Column(Unicode(10), nullable=False)
    __table_args__ = (UniqueConstraint('customer_id', 'location_code', name='_customer_location_uc'),
                     )