簡體   English   中英

如何防止使用相同值創建新 SQLAlchemy 對象的 UUID 主鍵

[英]How to prevent UUID primary key for new SQLAlchemy objects being created with the same value

我有一個 for 循環,它創建一個新的“行”對象,在將對象提交到 Postgres 數據庫中的表之前用數據填充屬性。 我要插入的表(以及對象)采用 UUID 的主鍵,只有在第一次提交后所有新創建的行對象中的循環的第一次迭代后,這個值保持不變。

我對解決方案有點迷茫,但是我認為這可能與我處理數據庫會話的方式有關。 在寫這篇文章時,我還注意到我在invite_usersinvite_user函數中使用了相同的變量名( new_user )。 雖然 Python 會認為它們在不同的范圍內(我認為),但我想知道 SQLALchemy 會話是否會?

請注意,我已經刪除了很多我認為在問題的上下文中是多余的代碼 - 主要是更多的列等。此外, invite_user函數在其他地方使用,因此invite_users僅用於批量“邀請”。

這是一個片段,顯示了表類定義和Column定義的開始:

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.dialects import postgresql
import uuid

Base = declarative_base()

class User(Base):
    __tablename__ = "users"

    id = Column(postgresql.UUID(as_uuid=True), default=uuid.uuid4(), primary_key=True)
    email = Column(String, unique=True)

這是我用來創建和銷毀會話的函數:

from contextlib import contextmanager
from sqlalchemy import create_engine

@contextmanager
def db_session(db_url):
    engine = create_engine(db_url, convert_unicode=True)
    connection = engine.connect()
    db_session = scoped_session(sessionmaker(autocommit=False, autoflush=True, bind=engine))
    yield db_session
    db_session.close()
    connection.close()

下面是遍歷 JSON 對象數組的函數的一部分:

def invite_users(json_dict):
    exceptions = {}

    with db_session(environ['CONNECTION_STRING']) as session:
        for new_user in json_dict['users']:
            try:
                invite_user(
                    session,
                    info['email_address']
                )
            # I'm catching exceptions and storing them to handle them later
            except Exception as e:
                exceptions[user_info['email_address']] = e
                pass

這是將行添加到會話並嘗試提交它的invite_user函數:

from project.database import * # this contains the User table class above
from project.exceptions import *

def invite_user(session, email):

    new_user = User(
        email=email
    )

    session.add(new_user)

    try:
        session.commit()
    except exc.IntegrityError as e:
        session.rollback()
        raise DuplicateViolation(f"User already invited") from None

所以我遍歷字典中的電子郵件地址( json_dict['emails'] )。 然后,我將每封電子郵件連同當前的數據庫session一起傳遞給用戶。 我這樣做是為了避免為每個invite_user調用創建一個會話,因為從性能角度來看,這似乎比在invite_user函數中創建一個新session更明智,因為這將導致許多會話被創建和銷毀。

我認為我的Column定義足以處理每次提交User行對象時新 UUID 的生成。 但是,如果我向invite_users函數傳遞多個電子郵件地址,第一個用戶會被添加一個新的UUID,第二個用戶會被分配相同的UUID。 如果我通過它一個電子郵件地址一切都很好

我不想依賴查詢數據庫中的現有行。 我完全依靠數據庫約束來防止重復,異常處理用於向用戶報告錯誤。

Column 的default參數狀態的 sqlalchemy 文檔

表示此列的默認值的標量、Python 可調用或 ColumnElement 表達式,如果在插入的 VALUES 子句中未指定此列,則將在插入時調用該表達式。

因此,與其提供將創建標量(常量)值的uuid.uuid4() ,不如僅提供可調用的uuid.uuid4 ,以便為每個插入調用它。

列插入/更新默認值中有對默認值的進一步討論

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM