SQLAlchemy 행 항목을 업데이트하는 방법?


138

가정의 표는 세 개의 열이 있습니다 username, password하고 no_of_logins.

사용자가 로그인을 시도하면 다음과 같은 쿼리가있는 항목을 확인합니다.

user = User.query.filter_by(username=form.username.data).first()

암호가 일치하면 더 진행합니다. 내가하고 싶은 것은 사용자가 로그인 한 횟수를 세는 것입니다. 따라서 그가 성공적으로 로그인 할 때마다 no_of_logins필드를 늘리고 다시 사용자 테이블에 저장하고 싶습니다 . SqlAlchemy로 업데이트 쿼리를 실행하는 방법을 잘 모르겠습니다.

답변:


132
user.no_of_logins += 1
session.commit()

12
stackoverflow.com/a/2334917/125507에 따르면 이것이 나쁜 방법입니다. 행이 아직 없으면 어떻게해야합니까?
endolith

6
endolith의 링크에 따라 user.no_of_logins += 1경쟁 조건을 만들 수 있습니다. 대신을 사용하십시오 user.no_of_logins = user.no_of_logins + 1. 후자의 올바른 방법은 다음과 같이 SQL로 변환됩니다 SET no_of_logins = no_of_logins + 1.
ChaimG

5
@ChaimG 나는 당신이 의미하는 것 같아요 user.no_of_logins = User.no_of_logins + 1, 다시 말하면 모델의 계측 된 속성을 사용하여 SQL 표현식을 생성합니다. 귀하의 의견은 동일한 경쟁 조건을 생성하는 두 가지 방법을 표시합니다.
Ilja Everilä '

2
그들은 아닙니다. 전자는 속성을 SQL 표현식으로 설정하고 후자는 파이썬에서 인플레 이스 추가를 수행하고 다시 레이스를 소개합니다.
Ilja Everilä

1
@ jayrizzo SERIALIZABLE 트랜잭션 격리 수준에 익숙하지는 않지만 제 이해에 따르면 in-place 추가를 사용하여 Python에서 추가를 수행 할 수 있습니다. 경쟁이있는 경우, 트랜잭션 중 하나가 성공하고 다른 하나는 실패하고 다시 시도해야합니다 (새로운 DB 상태). 그러나 SERIALIZABLE을 오해했을 수도 있습니다.
Ilja Everilä

343

UPDATE사용 하는 몇 가지 방법이 있습니다sqlalchemy

1) user.no_of_logins += 1
   session.commit()

2) session.query().\
       filter(User.username == form.username.data).\
       update({"no_of_logins": (User.no_of_logins +1)})
   session.commit()

3) conn = engine.connect()
   stmt = User.update().\
       values(no_of_logins=(User.no_of_logins + 1)).\
       where(User.username == form.username.data)
   conn.execute(stmt)

4) setattr(user, 'no_of_logins', user.no_of_logins+1)
   session.commit()

3
내가 사용 setattr(query_result, key, value)영약 SQLAlchemy의 일부 업데이트는 커밋 하였다. 이 패턴을 할인 할 이유가 있습니까?
Marc

2
@datamafia :을 사용할 수 있습니다 setattr(query_result, key, value). 이것은 쓰기와 정확히 동일합니다query_result.key = value
Nima Soroush

Thx @NimaSoroush, 그게 내가하는 일이며 그렇습니다.
Marc

8
이러한 경우의 차이점을 설명 할 수 있습니까? 감사!
하트셉수트

1
내가 사이에 오늘 우연히 한 가지 차이 @Hatshepsut 41/2 :에서입니다 groups.google.com/forum/#!topic/sqlalchemy/wGUuAy27otM
카스 프라 사드

13

허용 된 답변의 주석에서 중요한 문제를 명확히하는 예

나는 그것을 가지고 놀 때까지 그것을 이해하지 못했기 때문에 혼란스러워하는 다른 사람들도있을 것이라고 생각했습니다. 시작한 사람 id == 6no_of_logins == 30시작한 사용자를 작업하고 있다고 가정합니다 .

# 1 (bad)
user.no_of_logins += 1
# result: UPDATE user SET no_of_logins = 31 WHERE user.id = 6

# 2 (bad)
user.no_of_logins = user.no_of_logins + 1
# result: UPDATE user SET no_of_logins = 31 WHERE user.id = 6

# 3 (bad)
setattr(user, 'no_of_logins', user.no_of_logins + 1)
# result: UPDATE user SET no_of_logins = 31 WHERE user.id = 6

# 4 (ok)
user.no_of_logins = User.no_of_logins + 1
# result: UPDATE user SET no_of_logins = no_of_logins + 1 WHERE user.id = 6

# 5 (ok)
setattr(user, 'no_of_logins', User.no_of_logins + 1)
# result: UPDATE user SET no_of_logins = no_of_logins + 1 WHERE user.id = 6

요점

인스턴스 대신 클래스를 참조하면 SQLAlchemy가 증가하는 것에 대해 더 똑똑 해져서 파이썬 쪽이 아닌 데이터베이스 쪽에서 발생할 수 있습니다. 데이터 손상에 덜 취약하기 때문에 데이터베이스 내에서 수행하는 것이 좋습니다 (예 : 두 클라이언트가 동시에 두 개가 아닌 한 번만 순 결과로 증가하려고 시도 함). 잠금을 설정하거나 격리 수준을 높이면 파이썬에서 증분을 수행 할 수 있다고 가정하지만 필요하지 않은 이유는 무엇입니까?

경고

SQL과 같은 SQL을 생성하는 코드를 통해 두 번 증분하려는 경우 증분 SET no_of_logins = no_of_logins + 1사이를 커밋하거나 적어도 플러시해야합니다. 그렇지 않으면 총 한 번만 증가합니다.

# 6 (bad)
user.no_of_logins = User.no_of_logins + 1
user.no_of_logins = User.no_of_logins + 1
session.commit()
# result: UPDATE user SET no_of_logins = no_of_logins + 1 WHERE user.id = 6

# 7 (ok)
user.no_of_logins = User.no_of_logins + 1
session.flush()
# result: UPDATE user SET no_of_logins = no_of_logins + 1 WHERE user.id = 6
user.no_of_logins = User.no_of_logins + 1
session.commit()
# result: UPDATE user SET no_of_logins = no_of_logins + 1 WHERE user.id = 6

안녕하세요, 귀하의 답변에 감사드립니다 .int 변수 대신 문자열 변수를 업데이트하려고합니다. 어떻게합니까? 나는 sqlite 데이터베이스를 사용하고 있으며 내가 바꾸고 싶은 변수는 양식 제출을 통해 current_user에 있습니다.
dani bilel

1
@danibilel 꽤 철저한 문서를 확인하십시오. 학습서의이 부분에서는 문자열 필드를 업데이트합니다 ( docs.sqlalchemy.org/en/13/orm/…) . 그렇지 않으면, 당신은 당신이 구체적으로 붙어있는 것을 보여주는 새로운 질문을 게시하는 것이 좋습니다.
MarredCheese

링크 감사합니다, 하루 종일 검색 한 후 내 문제가 db.session.commit ()에 있다는 것을 알고 콘솔의 변경 사항을 유지하지 못합니다. 유사한 질문을 찾았지만 답변이 제공되지 않았습니다. 나를 위해, 실제 웹 응용 프로그램에서 그것은 더 나빠집니다! 변경 사항이 전혀 저장되지 않습니다. 긴 의견에 대해 죄송하지만 웹 사이트 정책으로 인해 질문을 추가 할 수 없으므로 도움을 주시면 감사하겠습니다.
다니엘 빌레

4

user=User.query.filter_by(username=form.username.data).first()명령문 의 도움으로 지정된 사용자를 user변수로 가져올 수 있습니다.

이제 새 객체 변수의 값을 변경하고 의 commit 메소드로 user.no_of_logins += 1변경 사항을 저장할 수 session있습니다.


2

전보 봇을 작성하고 업데이트 행에 문제가 있습니다. 모델이있는 경우이 예를 사용하십시오.

def update_state(chat_id, state):
    try:
        value = Users.query.filter(Users.chat_id == str(chat_id)).first()
        value.state = str(state)
        db.session.flush()
        db.session.commit()
        #db.session.close()
    except:
        print('Error in def update_state')

왜 사용 db.session.flush()합니까? >>> SQLAlchemy : flush ()와 commit ()의 차이점은 무엇입니까?


7
플러시는 커밋 직전에 중복됩니다. 커밋은 항상 암시 적으로 플러시됩니다. 많이는 Q / A에 말했듯이 당신은 연결 : " flush()항상 호출의 일부에라고 commit()"
Ilja Everilä에게
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.