sqlalchemy flush () 및 삽입 된 ID 가져 오기?


114

다음과 같이하고 싶습니다.

f = Foo(bar='x')
session.add(f)
session.flush()

# do additional queries using f.id before commit()
print f.id # should be not None

session.commit()

그러나 f.id이며 None나는 그것을 시도 할 때. 이 작업을 수행하려면 어떻게해야합니까?


2
를 사용하여 SA 엔진을 초기화 echo=True하고 플러시 시간에 어떤 SQL이 실행되는지 확인할 수 있습니까? 설명하는 내용 작동하고 ID를 제공 해야 하지만 f.id가 없음이되는 다른 문제가있을 수 있습니다.
Pavel Repin

답변:


63

샘플 코드는 그대로 작동해야합니다. SQLAlchemy는 f.id자동 생성 기본 키 열로 가정하여에 대한 값을 제공해야합니다 . 기본 키 속성은 flush()생성되는 즉시 프로세스 내에서 채워 지며에 대한 호출 commit()이 필요하지 않습니다. 따라서 여기에 대한 답은 다음 중 하나 이상에 있습니다.

  1. 매핑 세부 정보
  2. 사용중인 백엔드에 이상한 특성이있는 경우 (예 : SQLite는 복합 기본 키에 대해 정수 값을 생성하지 않음)
  3. 에코를 켤 때 내 보낸 SQL이 말하는 내용

1
맞습니다. 셸의 빠른 확인은 기본 키 필드에 값을 채우는 것을 보여줍니다. 실제로 작동하지 않는 이유를 조사해야합니다.
Eloff

3
"귀하의 샘플 코드는 값을 제공해야합니다."라는 말은 "당신이 가지고있는 코드가있는 그대로 작동 했어야했다"가 아니라 "처음에 id에 대한 값을 제공 했어야했습니다"라고 말하는 것처럼 들립니다. 세 번째 읽기 이후에만 전자가 아닌 후자를 의미한다는 것이 나에게 분명해졌습니다. 명확히 할 수 있습니까?
확률 적

126

나는 방금 동일한 문제를 겪었고 테스트 후 이러한 답변 중 어느 것도 충분하지 않다는 것을 발견했습니다.

현재 또는 sqlalchemy .6+부터는 매우 간단한 솔루션이 있습니다 (이전 버전에 존재하는지 여부는 알 수 없습니다.

session.refresh ()

따라서 코드는 다음과 같습니다.

f = Foo(bar=x)
session.add(f)
session.flush()
# At this point, the object f has been pushed to the DB, 
# and has been automatically assigned a unique primary key id

f.id
# is None

session.refresh(f)
# refresh updates given object in the session with its state in the DB
# (and can also only refresh certain attributes - search for documentation)

f.id
# is the automatically assigned primary key ID given in the database.

그렇게하는 방법입니다.


8
이것은 나를 위해 작동 할 수있는 대답에 가까워지고 있지만 다음 오류가 수신됩니다. InvalidRequestError : '<....>'인스턴스를 새로 고칠 수 없습니다. 플러시 후 인스턴스가 더 이상 존재하지 않는 것으로 나타납니다. 통찰력을 높이십시오.
PlaidFan 2011

1
당신은 내 엉덩이를 구했습니다. 나는 Django에서 오는 ORM을 다시 사용할 것이라고 생각하지 않습니다. flush () 명령은 문서화 된 IMHO로 작동하지 않습니다.
Marc

2
업데이트, 나는 sessionmaker(autoflush=True)콤보 w / refresh ()를 사용하여 행 ID를 제공했습니다. #grrr
Marc

5
와의 차이점을 이해하지 못하는 경우 다음 flush()commit()같은 좋은 설명이 있습니다. stackoverflow.com/a/4202016/1252290
Epoc

2
대신 @PlaidFan flush()사용 commit()과 오른쪽 그 이후 -로 새로 고침은 session.refresh(f)나를 위해 작동하고, 나는 SQLAlchemy의 버전을 사용0.6.7
리키 레위에게

20

모두 감사합니다. 열 매핑을 수정하여 문제를 해결했습니다. 나를 위해 autoincrement=True필요합니다.

유래:

id = Column('ID', Integer, primary_key=True, nullable=False)

수정 후 :

id = Column('ID', Integer, primary_key=True, autoincrement=True, nullable=True)

그때

session.flush()  
print(f.id)

괜찮아!


6

dpb가 제공하는 답변과 달리 새로 고침이 필요하지 않습니다. 일단 플러시하면 id 필드에 액세스 할 수 있으며 sqlalchemy는 백엔드에서 자동으로 생성 된 ID를 자동으로 새로 고칩니다.

나는이 문제에 직면하고 몇 가지 조사 후 정확한 이유를 알아 냈고, 내 모델은 정수 필드로 ID로 생성되었으며 내 양식에서는 ID가 hiddenfield로 표시되었습니다 (내 양식에 ID를 표시하고 싶지 않았기 때문에). 숨겨진 필드는 기본적으로 텍스트로 표시됩니다. widget = hiddenInput ())을 사용하여 양식을 integerfield로 변경하면 문제가 해결되었습니다.


1
언급했듯이 refresh () 만 나를 위해 일했습니다. 데이터 마이그레이션을 수행 할 때 FK를 채우기 위해 루프에 행 ID가 필요했습니다. 나는 커밋, 플러시, 세션 해킹 및 refresh ()의 모든 콤보를 시도 해봤습니다. 내 데이터는 매우 깨끗하고 SQLA가 그다지 좋지 않다는 것을 발견했습니다 (최소 5 개의 주요 ORMS에서 상당한 exp가 있음). add ()-> commit () / flush ()에 대한 행 ID를 얻으려고 5 시간 이상을 래핑합니다.
Marc

1

메서드 0를 호출하기 전에 ID 를 할당 하는 데 문제가있었습니다 session.add. 데이터베이스에서 ID를 올바르게 지정했지만 이후 세션에서 올바른 ID를 검색하지 못했습니다 session.flush().


-7

session.save_or_update(f)대신을 사용해보십시오 session.add(f).


1
save_or_update0.5 정도부터 사용되지 않습니다. session.add()해야합니다.
Pavel Repin
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.