SQLAlchemy 업데이트 작업의 우아한 방식
31431 단어 SQLAlchemy업데이트ORM일상 BUG
class Test(object):
def __init__(self):
self.a = ""
self.b = ""
if __name__ == "__main__":
obj1 = Test()
obj2 = Test()
obj2.a = "xixi"
obj2.b = "haha"
어떻게
obj1
대상의 메모리 주소를 바꾸지 않은 상황에서 obj2
대상의 속성 값을 모두 obj1
대상에게 부여합니까?당신은
__dict__
이라는 마술 방법으로 위의 요구를 실현할 수 있습니다.if __name__ == "__main__":
obj1 = Test()
obj2 = Test()
obj2.a = "xixi"
obj2.b = "haha"
print(obj1.__dict__)
for key in obj2.__dict__:
setattr(obj1, key, getattr(obj2, key))
완벽하다상술한 방식을 이해한 후에 우리는 문장의 주제에 들어간다.
class HttpProxyDao(object):
...
def update(self, update_obj):
try:
object_host = update_obj.ip
object_port = update_obj.port
proxyobj = self.session.query(HttpProxy).filter(HttpProxy.ip.like(object_host),
HttpProxy.port.like(object_port)).one_or_none()
if proxyobj:
for key in update_obj.__dict__:
# setattr(proxyobj, key, update_obj.__dict__[key])
# proxyobj.__setattr__(key, update_obj.__dict__[key]) #
setattr(proxyobj, key, getattr(update_obj, key))
self.session.commit()
return proxyobj
except Exception as e_update:
print("e_update:", e_update)
return None
다음 문장을 이용하여 테스트해 봅시다.
if __name__ == "__main__":
obj = HttpProxyDao()
httpobj = HttpProxy()
httpobj.ip = "963"
httpobj.port = "123"
httpobj.type = "test"
httpobj.speed = "966"
rest = obj.update(httpobj)
print(rest)
운행 후 놀랍게도 데이터베이스에 아무런 변화가 없다는 것을 발견하였다.방금 쓴 업데이트 방법이 전혀 업데이트 역할을 하지 못했다는 얘기다.
어떻게 된 거지?디버깅을 위해 몇 개의 문장을 씁니다.
def update(self, update_obj):
try:
object_host = update_obj.ip
object_port = update_obj.port
proxyobj = self.session.query(HttpProxy).filter(HttpProxy.ip.like(object_host),
HttpProxy.port.like(object_port)).one_or_none()
if proxyobj:
print(proxyobj.__dict__) #
for key in update_obj.__dict__:
setattr(proxyobj, key, getattr(update_obj, key))
print(proxyobj.__dict__) #
self.session.commit()
return proxyobj
except Exception as e_update:
print("e_update:", e_update)
return None
실행 결과:
{'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x0000014993B3D208>, 'survival_time': None, 'speed': None, 'anonymity': None, 'port': '123', 'ip': '963', 'verify_time': None, 'connection_time': None, 'type': '', 'server_address': None, 'country': None}
{'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x0000014993AD7048>, 'survival_time': None, 'speed': '966', 'anonymity': None, 'port': '123', 'ip': '963', 'verify_time': None, 'connection_time': None, 'type': 'test', 'server_address': None, 'country': None}
<data_acquisition.data_acquisition.domain.HttpProxy.HttpProxy object at 0x0000014993B3D1D0>
분명히 type,speed 두 속성의 값이 바뀌었는데 왜 수정하지 못했을까요?
자세히 보면 대상의 이름은 모두 같지만 메모리 주소는 다르다는 것을 알 수 있다.그래서 우리는proxyobj 대상에 반드시 하나의 속성이 있다고 판정하고 대상의 메모리 주소를 수정했다.이어서 등록 정보의 이름을 인쇄해 보겠습니다.
def update(self, update_obj):
try:
object_host = update_obj.ip
object_port = update_obj.port
proxyobj = self.session.query(HttpProxy).filter(HttpProxy.ip.like(object_host),
HttpProxy.port.like(object_port)).one_or_none()
if proxyobj:
for key in update_obj.__dict__:
print(key)
setattr(proxyobj, key, getattr(update_obj, key))
print(proxyobj.ip, " ")
self.session.commit()
return proxyobj
except Exception as e_update:
print("e_update:", e_update)
return None
실행 결과:
_sa_instance_state
ip
port
type
speed
역시
_sa_instance_state
는 무엇입니까?한 걸음 더 나아가 호기심을 가지고 살펴보자.
if proxyobj:
print(proxyobj.__dict__)
for key in update_obj.__dict__:
print(getattr(proxyobj, '_sa_instance_state'))
setattr(proxyobj, key, getattr(update_obj, key))
print(proxyobj.__dict__)
self.session.commit()
return proxyobj
{'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x000002437233D278>, 'survival_time': None, 'speed': None, 'anonymity': None, 'port': '123', 'ip': '963', 'verify_time': None, 'connection_time': None, 'type': '', 'server_address': None, 'country': None}
<sqlalchemy.orm.state.InstanceState object at 0x000002437233D278>
<sqlalchemy.orm.state.InstanceState object at 0x00000243722D60F0>
<sqlalchemy.orm.state.InstanceState object at 0x00000243722D60F0>
<sqlalchemy.orm.state.InstanceState object at 0x00000243722D60F0>
<sqlalchemy.orm.state.InstanceState object at 0x00000243722D60F0>
{'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x00000243722D60F0>, 'survival_time': None, 'speed': '966', 'anonymity': None, 'port': '123', 'ip': '963', 'verify_time': None, 'connection_time': None, 'type': 'test', 'server_address': None, 'country': None}
<data_acquisition.data_acquisition.domain.HttpProxy.HttpProxy object at 0x000002437233D240>
첫 번째 교체
_sa_instance_state
의 값은 proxyobj
대상의 메모리 주소였고 그 다음에 몇 번 수정되었다.추측_sa_instance_state
속성을 사용하면 proxyobj
대상의 메모리 주소가 될 것입니다.사용, 현재 우리는 이 속성을 필터하기만 하면 조작을 완성할 수 있습니다.이어서 코드를 수정합니다.
def update(self, update_obj):
try:
object_host = update_obj.ip
object_port = update_obj.port
proxyobj = self.session.query(HttpProxy).filter(HttpProxy.ip.like(object_host),
HttpProxy.port.like(object_port)).one_or_none()
if proxyobj:
print(proxyobj.__dict__)
for key in update_obj.__dict__:
if key == '_sa_instance_state':
continue
setattr(proxyobj, key, getattr(update_obj, key))
print(proxyobj.__dict__)
self.session.commit()
return proxyobj
except Exception as e_update:
print("e_update:", e_update)
return None
실행:
{'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x000001DEC414D2B0>, 'survival_time': None, 'speed': None, 'anonymity': None, 'port': '123', 'ip': '963', 'verify_time': None, 'connection_time': None, 'type': '', 'server_address': None, 'country': None}
{'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x000001DEC414D2B0>, 'survival_time': None, 'speed': '966', 'anonymity': None, 'port': '123', 'ip': '963', 'verify_time': None, 'connection_time': None, 'type': 'test', 'server_address': None, 'country': None}
<data_acquisition.data_acquisition.domain.HttpProxy.HttpProxy object at 0x000001DEC414D278>
됐어, 메모리 주소는 변하지 않았어.데이터베이스에 있는 값도 성공적으로 수정되었습니다.
끝말
이곳의 구덩이는
_sa_instance_state
이라는 속성입니다. 사실 이 속성은 처음에 그 예에 존재하지 않았기 때문에 이런 문제에 부딪혔을 때 결과가 이상하다는 것을 발견하면 키(속성 값)를 출력해서 보십시오.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
SQL ForeignKey Mismatch테이블 A에서 ForeignKey로 타 테이블 B의 column C를 가리키려 했더니 ForeignKey Mismatch가 뜨는 이유는: B란 테이블이 없거나 B란 테이블은 있는데 C란 column이 없거나 Colu...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.