[英]How to create a table with Interval as primary key in SQLAlchemy?
我正在嘗試使用 SQLAlchemy ORM 創建一個用於處理計費頻率的表,但我似乎不太高興
以下在 Postgres 中效果很好:
create table test_interval(
frequency interval primary key
);
insert into test_interval values ('1 MONTH'), ('1 YEAR');
select * from test_interval;
-- 0 years 1 mons 0 days 0 hours 0 mins 0.00 secs
-- 1 years 0 mons 0 days 0 hours 0 mins 0.00 secs
我現在正在嘗試使用此代碼在 SQLAlchemy 中實現相同的目標
from typing import Any
from sqlalchemy import Column, Interval, PrimaryKeyConstraint
from sqlalchemy.ext.declarative import as_declarative, declared_attr
@as_declarative()
class Base:
id: Any
__name__: str
# Generate __tablename__ automatically
@declared_attr
def __tablename__(cls) -> str:
return cls.__name__.lower()
class BillingFrequency(Base):
__tablename__ = "billing_frequency"
# I've also tried this
# __table_args__ = (PrimaryKeyConstraint("frequency"),)
# frequency: Column(Interval(native=True), index=True, unique=True, nullable=False)
frequency: Column(Interval(native=True), primary_key=True, nullable=False)
# seed.py
# -- I've not even managed to create the table so this is yet untested --
from sqlalchemy.orm import Session
from sqlalchemy.dialects.postgresql import insert
from app.models import BillingFrequency
def seed_billing(db: Session) -> None:
# Monthy frequency
stmt_month = insert(BillingFrequency).values(frequency="1 MONTH")
stmt_month = stmt_month.on_conflict_do_nothing(
index_elements=[BillingFrequency.frequency],
)
db.add(stmt_month)
# Year frequency
stmt_year = insert(BillingFrequency).values(frequency="1 YEAR")
stmt_year = stmt_year.on_conflict_do_nothing(
index_elements=[BillingFrequency.frequency],
)
db.add(stmt_year)
db.commit()
這導致以下錯誤:
sqlalchemy.exc.ArgumentError: Mapper mapped class BillingFrequency->billing_frequency could not assemble any primary key columns for mapped table 'billing_frequency'
如果我嘗試使用__table_args__
使用主鍵, __table_args__
出現以下錯誤。
KeyError: 'frequency'
不知道如何處理這個。 這在純 SQL 中非常簡單,但 ORM 讓它變得很痛苦。
您犯了兩個小錯誤,但不幸的是,對於此類錯誤,錯誤消息有點神秘。
第一個問題是您使用...: Column
即作為類型而不是...= Column
分配值。 這就是導致sqlalchemy.exc.ArgumentError
和KeyError: 'frequency'
,SQLAlchemy 不知道該列存在,因為它沒有查看 Column 數據的類型注釋。
您犯的第二個錯誤是使用db.add(…)
作為語句,您應該使用db.execute(…)
。 使用db.add
會出現以下錯誤:
AttributeError: 'Insert' object has no attribute '_sa_instance_state'
The above exception was the direct cause of the following exception:
...
sqlalchemy.orm.exc.UnmappedInstanceError: Class 'sqlalchemy.dialects.postgresql.dml.Insert' is not mapped
通過這些更改,您的代碼應如下所示:
from typing import Any
from sqlalchemy import Column, Interval, PrimaryKeyConstraint
from sqlalchemy.ext.declarative import as_declarative, declared_attr
@as_declarative()
class Base:
id: Any
__name__: str
# Generate __tablename__ automatically
@declared_attr
def __tablename__(cls) -> str:
return cls.__name__.lower()
class BillingFrequency(Base):
__tablename__ = "billing_frequency"
frequency = Column(Interval(native=True), primary_key=True, nullable=False)
# seed.py
# -- I've not even managed to create the table so this is yet untested --
from sqlalchemy.orm import Session
from sqlalchemy.dialects.postgresql import insert
from app.models import BillingFrequency
def seed_billing(db: Session) -> None:
# Monthy frequency
stmt_month = insert(BillingFrequency).values(frequency="1 MONTH")
stmt_month = stmt_month.on_conflict_do_nothing(
index_elements=[BillingFrequency.frequency],
)
db.execute(stmt_month)
# Year frequency
stmt_year = insert(BillingFrequency).values(frequency="1 YEAR")
stmt_year = stmt_year.on_conflict_do_nothing(
index_elements=[BillingFrequency.frequency],
)
db.execute(stmt_year)
db.commit()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.