SQLAlchemy 업데이트 작업의 우아한 방식

SQLAlchemy 업데이트 작업에 대해 설명하기 전에 다음 사항을 살펴보겠습니다.
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이라는 속성입니다. 사실 이 속성은 처음에 그 예에 존재하지 않았기 때문에 이런 문제에 부딪혔을 때 결과가 이상하다는 것을 발견하면 키(속성 값)를 출력해서 보십시오.

좋은 웹페이지 즐겨찾기