• python orm sqlalchemy를 써보자[1.1.x]기준 2부

    2017. 8. 6. 14:32

    by. 위지원

    [1] 리스트와 스칼라 반환하기


    query 객체의 all,one,first 메서드를 이용하여 non-iterator값을 반환한다.

    1.first는 list를 반환한다.


    query=session.query(User).filter(User.name.like('%air')).order_by(User.id)

    query.all()


    2.first는 첫번째 값만 scalar로 가져온다.


    query.first()


    3.one은 모든 행을참조하여 식별자를 값으로 가지지않거나 중복행이 있는 경우 에러생성


    from sqlalchemy.orm.exc import MultipleResultsFound try: user = query.one() except MultipleResultsFound, e: print e from sqlalchemy.orm.exc import NoResultFound try: user = query.filter(User.id == 99).one() except NoResultFound, e: print e


    [2] 문자로 sql을 사용할 수있음


    -예를들어 filter()와 orfer_by()를 사용하는 구문에서 filter("id<224") order_by("id") 이렇게 사용 할 수 있다.


    -콜론을 이용하여 매핑을 이용할 수 있다.

    filter("id<:value and name=:name").params(value=1234,name="wee") 


    -stmt

    from_statemnet("select * from users where name=:name").params(name="wee")


    [3] .count()로 숫자를 카운팅할 수있다.

    -session.query(User).filter(User.name.like('haru%')).count()

    -func.count(User.name) 로 함수안에 컬럼을 지정할 수있다.

    -pk로 카운트를 하면 select from이 필요없다


    [4]관계 만들기 http://weejw.tistory.com/84 <-다시공부해봤다..이해도 부족

    -테이블 설계시 바로 관계를 정의

    user_id = Column(Integer, ForeignKey('users.id'))

    user = relationship("User", backref=backref('addresses', order_by=id))



    class Address(Base):
    ...     __tablename__ = 'addresses'
    ...     id = Column(Integer, primary_key=True)
    ...     email_address = Column(String, nullable=False)
    ...     user_id = Column(Integer, ForeignKey('users.id'))
    ...
    ...     user = relationship("User", back_populates="addresses")

    -backref , back_populates는 역으로도 참조가 가능하도록 함 

    -'addresses'처럼 문자열로 선언하는 이유는 선언되지 않은 클래스에 대한 오류때문

    -외래키 컬럼은 자동으로 cascade

    -관계가 맺어졌을때 는 객체에서 클래스를 참조하면 된다.

    (ex. user와 address사이의 관계가 있을 때 wee=user("wee") 라는 객체생성시 wee.address로 address테이블 참조


    [5]join과 함께 쿼리하기

    -filter를 이용하여 join을 할 수 있다.

    for u, a in session.query(User, Address).\ filter(User.id==Address.user_id).\ filter(Address.email_address=='jack@gmail.com')


    -query.join()을 이용할 수 있다. (외래키 기준으로 join)

    session.query(User).join(Address).\ filter(Address.email_address=='jack@gmail.com')

    만약 외래키가 없다면 아래와같이 명시해줘야한다.

    query.join(Address, User.id==Address.user_id) query.join(User.addresses) query.join(Address, User.addresses) query.join('addresses')

    -outer join은 outerjoin()으로 하면된다.

    query.outerjoin(User.addresses)


    [6] 별칭 사용하기

    -aliased()를 이용한다.

    from sqlalchemy.orm import aliased adalias1 = aliased(Address) adalias2 = aliased(Address)


    [7] 서브쿼리의 이용

    - 아래와 같은쿼리를 alchemay로 변경할 수있다.

    SELECT users.*, adr_count.address_count

    FROM users LEFT OUTER JOIN ( SELECT user_id, count(*) AS address_count FROM addresses GROUP BY user_id ) AS adr_count ON users.id = adr_count.user_id



    변경후


    from sqlalchemy.sql import func stmt = session.query(Address.user_id, func.count('*').label('address_count')).\ group_by(Address.user_id).subquery()


    for u, count in session.query(User, stmt.c.address_count).\ outerjoin(stmt, User.id==stmt.c.user_id).order_by(User.id): print u, count


    이때 서브쿼리로 가져온걸 컬럼으로 이용해서 사용할 수 있다. aliased로 별칭을 지정해 이용


    stmt = session.query(Address).\ filter(Address.email_address != 'jack@yahoo.com').\ subquery() adalias = aliased(Address, stmt) for user, address in session.query(User, adalias).\ join(adalias, User.addresses): print user, address



    [8] exists 이용

    from sqlalchemy.sql import exists stmt = exists().where(Address.user_id==User.id)


    [9]any 이용

    특정기준을 주어 제한적 매칭을 가능케함

        filter(User.addresses.any(Address.email_address.like('%gmail%'))):


    has도 동일한기능을 한다. (대신 다대일관계에서 사용)
    filter(~Address.user.has(User.name=='jack')).all()

    [10]contains 이용

    query.filter(User.addresses.contains(someaddress))



    [11] 선행로딩

    lazy loading의 반대로 user.addresses 일경우 , addresses는 실제 adresses에 대한 쿼리가 실행될때 호출하지말고 user를 불렀을때 바로호출하도록 하는것이다. (쿼리호출의 수를 줄일 수 있다)


    -서브쿼리로딩

    jack = session.query(User).\ options(subqueryload(User.addresses)).\ filter_by(name='jack').one()


    -연결된 로딩

    from sqlalchemy.orm import joinedload jack = session.query(User).\ options(joinedload(User.addresses)).\ filter_by(name='jack').one()



    joineload는 n:1의 관계에서 적합하고 subqueryload()는 관계컬렉션을 가져올때 적합.


    -명시적join_선행로딩

    n:1 객체를 미리 불러와 동일 객체에 필터링 할 경우 유용

    jack_addresses = session.query(Address).\ join(Address.user).\ filter(User.name=='jack').\ options(contains_eager(Address.user)).\ all()


    [12]삭제하기

    -delete(객체)

    alchemy는 제거를 종속적으로 하지 않는다.그래서 관계에서 행동자체를 변경시켜야한다.

    존재하는 관계를 제거할때에는 맵핑을 완전히 새로시작해야한다.


    1.session을 닫는다

    session.close()


    2.새로운 declarative_base() 객체를 생성한다.

    Base=declarative_base()


    3.User와 address 클래스를 선언한다.

    class User(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) name = Column(String) fullname = Column(String) password = Column(String) addresses = relationship("Address", backref='user', cascade="all, delete, delete-orphan") def __repr__(self): return "<User('%s','%s','%s'>" % (self.name, self.fullname, self.password)


    class Address(Base): __tablename__ = 'addresses' id = Column(Integer, primary_key=True) email_address = Column(String, nullable=False) user_id = Column(Integer, ForeignKey('users.id')) def __repr__(self): return "<Address('%s')>" % self.email_address


    '2017년 > Database' 카테고리의 다른 글

    mysql innodb table row rock에 대해 알아보자  (0) 2017.08.11
    sqlite에서 지원하지 않는! 것들!  (0) 2017.08.10
    ggplot에 대해 알아보자  (0) 2017.08.04
    R이란? 2부  (0) 2017.08.02
    HBASE란?  (0) 2017.07.21