기본 콘텐츠로 건너뛰기

[MySQL-Flask SqlAlchemy] Python 으로 ORM 완벽사용 (2)

[MySQL-Flask SqlAlchemy] Python 으로 ORM 완벽사용 (2)

건프의 소소한 개발이야기

건강한프로그래머 2016. 12. 1. 19:24

안녕하세요, 건프입니다.

앞에서 ORM 의 개념과, 클래스 지정 방법에 대해서 알아봤습니다.

이번에는 ORM 방법으로 Flask-Sqlalchemy 에서는 어떤식으로 DB 에서 Query 하는지를 알아보고, 실전에서 자주 사용하는 여러가지 기법들에 대해서도 간단하게 메모해보려고 합니다.

첫번째로 일반적으로 테이블에서 값을 가져오는 Query 인 Select 하는 방법을 먼저 알아봅니다.

def search_events_by_userid (user_id):

"""

user_id 를 기준으로 event 찾기, all 로 찾음

"""

return TravelEvent.query.filter_by( user_id =user_id).all()

def search_event_by_eventid (event_id):

"""

event_id 를 기준으로 event 를 찾기. 한개만 리턴

"""

return TravelEvent.query.filter_by( event_id =event_id).first()

이렇게 두개의 예제가 간단하게 확인할 수 있는 방법입니다.

search_events_by_userid 로 정의된 함수는 TravelEvent 라는 디비클래스를 이용해서 쿼리를 날립니다.

저기 있는 TravelEvent 라는 클래스는 ORM 완벽사용 (1) 에서 처럼 정의한 db 클래스입니다.

from datetime import datetime

class TravelEvent (db.Model):

__tablename__ = 'travel_event'

__table_args__ = { 'mysql_collate' : 'utf8_general_ci' }

event_id = db.Column(db.Integer , primary_key = True , unique = True , autoincrement = True ) # primary key for event table

user_id = db.Column(db.String( 30 )) # 어느 사용자가 이벤트를 오픈했는지

course_id = db.Column(db.Integer) # 어느 코스를 사용하는지, 해당 코스의 detail 정보를 모두 가져올 수 있다

title = db.Column(db.String( 30 )) # 해당 모집글의 제목정보

description = db.Column(db.String( 1000 )) # 사용자가 작성할 이벤트의 설명글

max_tourist = db.Column(db.Integer) # 최대 모집자 수

current_tourist = db.Column(db.Integer) # 현재 모집자 수

travel_start_time = db.Column(db.DateTime) # 여행 시작 날짜와 시간

travel_end_time = db.Column(db.DateTime) # 여행 끝 날짜와 시간

event_end_time = db.Column(db.DateTime) # 모집이 끝나는 시간, 모집글이 등록되는 순간부터 모집 시

status = db.Column(db.Integer) # 모집여부, 0: 모집 끝, 1:모집 진행중

hash_tag = db.Column(db.String( 200 )) # 검색을 위해서 이벤트가 지나가는 경로에 대한 해시태그

created = db.Column(db.DateTime)

def __init__ ( self , user_id , course_id , title , description , max_tourist , start_time , end_time , event_end_time , hash_tag):

self .user_id = user_id

self .course_id = course_id

self .title = title

self .description = description

self .max_tourist = max_tourist

self .current_tourist = 1 # 처음에는 무조건 본인 한명

self .travel_start_time = start_time

self .travel_end_time = end_time

self .event_end_time = event_end_time

self .status = 1 # 처음에 등록하면 무조건 모집 중 상태

self .hash_tag = hash_tag

self .created = datetime.now() # 만들면 현재 날짜를 등록

def as_dict ( self ):

return {x.name: getattr ( self , x.name) for x in self .__table__.columns}

별로 중요하진 않지만, 모호하게 설명하는 것을 안좋아해서 첨부합니다.

TravelEvent.query.filter_by( user_id =user_id).all()

TravelEvent.query 객체를 부른다음, filter_by() 함수에서 user_id 가 매개변수로 들어온 user_id 에 매칭이 되는 애들을 찾아서, all() : 모두 리턴해달라.

TravelEvent.query.filter_by( event_id =event_id).first()

first() : 첫번째에 매칭되는 인스턴스만 달라

어떤 식으로 사용되는지 아시겠나요?

filter_by 의 경우 sql 에서 where 문을 생성해주는 것이라고 생각하면 될 것 같습니다.

여러 조건을 한번에 query 하고 싶은 경우에는 어떻게 할까요?

예를들어 where a == 'a' and b == 'b' 요렇게 말이죠.

from sqlalchemy import and_

queries = CourseDetail.query.filter(and_(CourseDetail.content_id == item[ 'content_id' ] ,

CourseDetail.sequence_id == item[ 'sequence_id' ])).all()

이렇게 진행하시면 됩니다. filter() 함수 안에서 flask-sqlalchemy 를 설치하면 함께 설치되는 sqlalchemy 안에 있는 and_ 함수를 이용하는 것이죠.

CourseDetail 로 정의되어 있는 Table 에서 content_id 와 sequence_id 가 정확히 일치되는 모든 인스턴스를 찾아서 리턴해주는 역할을 하게 됩니다.

정렬은 어떻게할까요?

일반적으로 정렬은 sql 문에서 order by 로 작업합니다.

new_course_id = CourseMeta.query.order_by(CourseMeta.created.desc()).first().course_id

이렇게 하시면 동작합니다.

CourseMeta 테이블에서 created 칼럼을 내림차순으로 정렬한 뒤에,

첫번째 인스턴스의

course_id 를 반환하는 예제입니다.

offset 과 limit 도 지정할 수 있을까요?

네 가능합니다.

def search_course_reviews (course_id , off_set= 0 , limit_num= 20 ):

if limit_num is None :

limit_num = 20

return CourseReview.query.filter_by( course_id =course_id).order_by(CourseReview.created.desc()).offset(off_set).limit(limit_num)

이 함수는 CourseReview 라는 테이블에서 course_id 로 필터하고, created 를 내림차순으로 정렬한뒤, offset 을 줘서 앞에서부터 스킵할 인스턴스 단위를 전달합니다. limit 는 한번에 가져올 인스턴스의 최대량을 의미하게 되죠.

이러한 방법은 sql 에서도 limit, offset 기능을 사용하는 것으로 예상하고, MongoDB 에서는 skip () 이라는 함수로 제공되는 것 같더군요?

클라이언트에서 버튼을 누르면 페이지나 내용물을 추가로 로딩하는 기능을 구현할때 유용합니다.

그렇다면 어떻게 인스턴스를 추가(Insert) 할까요?

from app import db

from app.models.event import TravelEvent

def add_new_event (new_event_object , course_id):

new_event = TravelEvent(new_event_object[ 'user_id' ] ,

course_id ,

new_event_object[ 'title' ] ,

new_event_object[ 'description' ] ,

new_event_object[ 'max_tourist' ] ,

new_event_object[ 'start_time' ] ,

new_event_object[ 'end_time' ] ,

new_event_object[ 'event_end_time' ] ,

new_event_object[ 'hash_tag' ])

db.session.add(new_event)

db.session.commit()

이 예제는 TravelEvent 테이블에 새로운 인스턴스를 추가하는 예제입니다.

TravelEvent 테이블을 클래스로 매핑했고(ORM) 클래스의 인스턴스를 만들때 생성자에 넣어야 할 것들을 정의했습니다.

그렇게 new_event 를 정의했고,

db.session.add() 함수에 해당 인스턴스를 넘긴뒤에

db.session.commit() 명령을 수행하면 됩니다.

db 객체는 ORM 완벽사용(1) 에서 봤듯이 app/__init__.py 안에 있던, 그 DB 객체를 가져온 것입니다.

없애는 것은 (delete) insert 와 워낙 닮았기 때문에 따로 언급하지 않겠습니다.

이미 넣었던 인스턴스의 정보를 어떻게 업데이트(Update) 하나요?

def user_join_event (user_id , event_id):

"""

유저가 이벤트에 참여하는 행동을 합니다

"""

new_user_bag = UserBag(user_id , 1 , event_id)

db.session.add(new_user_bag)

db.session.commit()

print (user_id , " 의 UserBag 에 " , event_id , " 를 추가했습니다" )

event = search_event_by_eventid(event_id)

current_tourist = event.current_tourist

if current_tourist + 1 <= event.max_tourist:

event.current_tourist=(event.current_tourist+ 1 )

db.session.commit()

return True

else :

# 이미 모집인원이 꽉차버림..

return False

다른 코드는 보지말고 우리가 원하는 update 하는 코드만 살펴보겠습니다.

event = search_event_by_eventid(event_id)

이렇게 해서 event_id 로 쿼리한 결과 인스턴스를 받아냅니다.

current_tourist = event.current_tourist

이렇게 하면, event 객체 안에 있는 현재 모집된 여행자수의 값을 받을 수 있습니다.

if current_tourist + 1 <= event.max_tourist:

따라서 이렇게 if 분기 연산을 진행할 수 있습니다.

event.current_tourist=(event.current_tourist+1)

db.session.commit()

event.current_tourist 맴버변수의 값을 새로운 값으로 업데이트 해주고

db.session.commit() 을 날려주면 업데이트가 완료됩니다!

사용하면 사용할 수록 ORM 의 뼈대가 되는 db.Model 의 역할이 너무나도 대단하는 생각이 듭니다. ㅎㅎ

이렇게 Flask-sqlalchemy 를 이용해 ORM 방법으로 디비를 손쉽게 관리하는 방법에 대해서 메모해보았습니다.

예전에 PHP 로 디비작업을 할때는 어떻게든 sql query 문을 객체지향적으로 짜보려고, 쿼리문을 만드는 make 함수를 두고, 테이블 이름과 칼럼명과 값을 넘겨가면서 객체지향적으로 짜보려는 노력을 했었었는데

Python 에서는 위와 같이 이미 정형화된 패턴이 있기 때문에 정말 편한것 같습니다! 갓파이썬

실전적으로 도움이 되기 위해서 제가 진행했었던 프로젝트를 예제로 따와서 전체적인 맥락은 볼 수 없어 불편하시겠지만

ORM 을 사용하는 방법을 익히는데는 큰 무리가 없을 것이라 생각합니다.

질문은 언제나 환영합니다.

도움이 되었길 바랍니다.

고맙습니다 :)

from http://ljs93kr.tistory.com/60 by ccl(A) rewrite - 2020-03-06 13:54:20

댓글

이 블로그의 인기 게시물

Coupang CS Systems 채용 정보: 쿠팡 운용 관리 시스템을 구축 하고...

Coupang CS Systems 채용 정보: 쿠팡 운용 관리 시스템을 구축 하고... Global Operation Technology는 상품을 고객에게 지연 없이 전달 될 수 있도록 하는 조직입니다. 1997년, 초창기 아마존에 입사한다고 상상해보세요. 그 당시 누구도 e-commerce 산업이, 아마존이라는 회사가 지금처럼 성장하리라고는 생각하지 못했을 것입니다. 하지만, 그 당시 아마존을 선택한 사람들은 e-commerce 산업을 개척했고, 아마존을 세계적인 회사로 성장시켰습니다. 2016년 '아시아의 아마존'으로 성장하고 있는 쿠팡, 당신에게 매력적인 선택이 아닐까요? Global Operation Technology: eCommerce에서 주문을 한 뒤 벌어지는 상황에 대해서 호기심을 가져보신 적이 있나요? Global Operation Technology는 상품을 고객에게 지연 없이 전달 될 수 있도록 하는 조직입니다. 매일 최첨단 소프트웨어 기술을 이용해 고객의 주문을 받고 상품을 어느 창고에서 출고 시킬지, 포장을 하나의 박스 또는 여러 개로 나눌 것인지, 어떤 배송 루트를 선택하고 어떻게 고객에게 배송 상태를 보여줄지 결정하는 시스템과 서비스를 개발 합니다. What Global Operations Technology does: CS and C-Returns System 적극적 고객서비스를 바탕으로 고객의 목소리를 통해 끊임없이 고객 에게 서비스를 제공하고 Andon 메커니즘을 통해 고객의 목소리를 회사 전체와 공유합니다. 그리고 고객 문제 해결과 구매 이후 벌어질 수 있는 고객 문제를 사전에 예방하기 위한 시스템 개발을 통해 미래의 상황을 예측 합니다. Tranportation System TSP (Traveling Salesman Problem) 와 같은 CS 최적화 관리 문제를 다룹니다.배송 물품의 실시간 추적, 3P 하드웨어와 소프트웨어를 통합, 각 배송 루트에 할당되는 물량 예측하고 T...

스프링 프레임워크(Spring Framework)란?

스프링 프레임워크(Spring Framework)란? "코드로 배우느 스프링 웹 프로젝트"책을 개인 공부 후 자료를 남기기 위한 목적이기에 내용 상에 오류가 있을 수 있습니다. '스프링 프레임워크'가 무엇인지 말 할 수 있고, 해당 프레임워크의 특징 및 장단점을 설명할 수 잇는 것을 목표로합니다. 1. 프레임워크란? 2. 스프링 프레임워크 "뼈대나 근간을 이루는 코드들의 묶음" Spring(Java의 웹 프레임워크), Django(Python의 웹 프레임워크), Flask(Python의 마이크로 웹 프레임워크), Ruby on rails(Ruby의 웹 프레임워크), .NET Framework, Node.js(Express.js 프레임워크) 등등. 프레임워 워크 종류 : 3. 개발 시간을 단축할 수 있다. 2. 일정한 품질이 보장된 결과물을 얻을 수 있다. 1. 실력이 부족한 개발자라 허다러도 반쯤 완성한 상태에서 필요한 부분을 조립하는 형태의 개발이 가능하다. 프레임워크를 사용하면 크게 다음 3가지의 장점 이 있습니다. 프레임워크 이용 한다는 의미 : 프로그램의 기본 흐름이나 구조를 정하고, 모든 팀원이 이 구조에 자신의 코드를 추가하는 방식으로 개발 한다. => 이러한 상황을 극복하기 위한 코드의 결과물이 '프레임워크' 입니다. 개발자는 각 개개인의 능력차이가 크고, 따라서 개발자 구성에 따라서 프로젝트의 결과 차이가 큽니다. 2. 스프링 프레임워크(Spring Framework) 자바 플랫폼을 위한 오픈 소스 애플리케이션 스프링의 다른 프레임워크와 가장 큰 차이점은 다른 프레임워크들의 포용 입니다. 이는 다시말해 기본 뼈대를 흔들지 않고, 여러 종류의 프레임워크를 혼용해서 사용할 수 있다는 점입니다. 대한민국 공공기관의 웹 서비스 개발 시 사용을 권장하고 있는 전자정부 표준프레임워크 이다. 여러 프레임워크들 중 자바(JAV...

Flask 18. jQuery와 ajax

Flask 18. jQuery와 ajax 현재 우리는 api를 만들고 있다. api를 사용하기 위해서는 ajax를 사용해야한다. 그리고 ajax를 편하게 쓸 수 있도록 도와주는 것이 jquery라이브러리이다. ajax는 비동기로 서버에 요청할 수 있다. 브라우저에 XMLHttpRequest객체가 있어서 이것을 사용해서 서버에 데이터를 요청할 수 있다. 기존에는 웹에 접근할 때 주소에다가 서버의 주소를 씀으로써 데이터(페이지)를 요청할 수 있고, form을 만드는 방법이 있다. 이러한 방법들은 페이지 이동이 일어나서 서버에서 무조건 응답으로 웹페이지를 만들어서 응답해야하는 단점이 있었다 그러나 api를 사용하면 리소스 중심으로 데이터의 이동만 일어난다. 클라이언트는 데이터만 받기 때문에 데이터로 웹을 만들어야한다. 화면은 이미 만들어져있는 상태에서 비동기로 화면을 전환하지 않고, 서버에 데이터 요청을 한 후 그 데이터를 기반으로 웹에 그 데이터를 반영하는 것이다. 이것들은 백그라운드에서 일어난다. 이것을 위해서는 자바스크립트를 이용해야하고 jquery를 이용할 것이다. jquery는 여러 셀렉터를 사용할 수 있어서 편하다. 자바스크립트 작업을 좀더 생산성 좋게 작업할 수 있도록 해준다. 가장 큰 특징은 ajax요청을 아주 쉽게 할 수 있다. 정리 비동기 요청을 위해서 ajax를 사용할 것이고, 그러나 순수자바스크립트는 어렵기 때문에 jquery를 사용할 것이다. 공유하기 글 요소 저작자표시 from http://ohdowon064.tistory.com/134 by ccl(A) rewrite - 2020-03-24 10:54:10