1) SQL Alchemy와 ORM
- ORM
데이터베이스에 객체를 통해 접근하는 방법을 ORM (Object Relational Mapping, 객체 관계 매핑)이라고 한다.
ORM은 SQL 질의어 없이 DB를 다룰 수 있도록 도와준다.
아래와 같은 테이블이 있다고 해보자. 테이블 명은 user다.
name | age |
hayan | 25 |
eunsol | 26 |
user 테이블에 대한 아래 두 코드는 같은 행위를 수행하는 코드이다.
* SQL쿼리문: INSERT INTO user (name, age) VALUES('hayan', 25);
* ORM: member = Member()
member.name ='hayan'
member.age = 25
db.session.add(member)
db.session.commit()
ORM으로 표현하는 것이 더 복잡해보인다..
그렇지만 DB에 대한 큰 고민 없이 DB를 코드로 다룰 수 있다는 장점,
테이블 구조가 변경될 때 ORM 모델만 수정하면 된다는 장점,
코드로 작성하기 때문에 쿼리를 직관적으로 이해할 수 있다는 장점이 있다. 고 한다. 난 잘 모르겟지만 ㅎ
- SQL Alchemy
파이썬 ORM 라이브러리로, 파이썬 코드에서 DB와 연결하기 위해 사용가능한 라이브러리다.
이번 포스팅의 아래쪽에서 더 자세히 다룰 것이다.
2) DB와 Model
member1 = Member(name='hayan', age='25')
db.session.add(member1)
위 코드에서 Member는 파이썬 클래스이며, DB의 Member 테이블과 매핑하여 사용한다.
DB의 테이블과 매핑되는 클래스는 모델 이라고 한다.
- ORM Model
from db_connect import db
class Member(db.Model):
__tablename__ = 'user' # 테이블 이름 명시
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(20), nullable=False)
age = db.Column(db.Integer, nullable=False)
id, name, age는 DB 테이블 컬럼을 명시해준다.
해당하는 DB를 다룰 때, Member 클래스로 접근한다.
3) Query - SQL Alchemy
- 간단한 CRUD
아래와 같은 Model이 있을 때
class Member(db.Model):
__tablename__ = 'user' # 테이블 이름 명시
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(20), nullable=False)
age = db.Column(db.Integer, nullable=False)
(1) Create
member = Member()
member.id = 1
member.name = 'hayan'
member.age = 25
db.session.add(member)
db.session.commit()
Member 객체를 생성하여 . 을 이용해 컬럼에 접근하여 값을 추가할 수 있다.
db.session.add(member)로 추가해주고, commit()을 하여 저장을 완료한다.
(2) Read
member = db.session.query(Member)
.filter(Member.name == 'hayan').all()
데이터를 가져올 때 기본적으로 db.session.query(Member)를 사용한다.
근데 이건 Member.query 처럼 더 간단하게 쓸 수도 있다.
.filter 함수를 사용하여 name이 hayan인 데이터를 받아오는데, all()은 데이터를 리스트로 반환한다.
(3) Update
db.session.query(Member)
.filter(Member.name == 'hayan').all()
member.name = 'kong'
db.session.commit()
name이 hayan인 데이터의 name을 kong으로 바꿔준다!
(4) Delete
me = db.session.query(Member)
.filter(Member.name == 'hayan').first()
db.session.delete(me)
db.session.commit()
name이 hayan인 데이터를 지워주는데, first()는 하나의 값만을 가져온다.
db.session.delete()를 사용하여 지워준다.
- 다양한 Query 사용법
(1) equal
@app.route('/')
def list():
member_list = Member.query.filter(Member.name == 'hayan')
return " ".join(i.name for i in member_list)
equal은 == 를 사용한다. name이 hayan인 데이터들을 불러온다.
(2) not equal
@app.route('/')
def list():
member_list = Member.query.filter(Member.name != 'hayan')
return " ".join(i.name for i in member_list)
not equal은 !=를 사용한다. name이 hayan이 아닌 데이터들을 불러온다.
(3) like
@app.route('/')
def list():
member_list = Member.query.filter(Member.name.like('hayan'))
return " ".join(i.name for i in member_list)
like는 해당 문자열이 포함된 모든 데이터를 불러온다. hayan 123, hayanee 등등
'%hayan%' 을 쓴다면 hayan 앞,뒤에 어떤 문자열이 있든 hayan이 포함된 데이터들을 가져온다.
(4) in
@app.route('/')
def list():
member_list = Member.query.filter(Member.name.in_(['hayan', 'kong']))
return " ".join(i.name for i in member_list)
in을 사용하려면 Member.name.in_ 이렇게 언더바도 같이 써줘야한다.
name이 hayan, kong인 데이터들을 불러온다.
(5) not in
@app.route('/')
def list():
member_list = Member.query.filter(~Member.name.in_(['hayan', 'kong']))
return " ".join(i.name for i in member_list)
not in을 쓸 때는 Member.name.in_ 앞에 ~ 를 붙여줘야한다.
~Member.name.in_
name이 hayan, kong인 데이터는 불러오지 않는다.
(6) is null
@app.route('/')
def list():
member_list = Member.query.filter(Member.name == None)
return " ".join(i.name for i in member_list)
일반 SQL문에서 is null이라고 쓰는 것을 우리는 None을 써서 알아낼 수 있다. name컬럼이 null인 데이터를 불러온다.
(7) is not null
@app.route('/')
def list():
member_list = Member.query.filter(Member.name != None)
return " ".join(i.name for i in member_list)
is not null은 !=None이다. name컬럼이 비어있지 않은 데이터를 가져온다.
(8) and
from sqlalchemy import and_
@app.route('/')
def list():
member_list = Member.query.filter(and_(Member.name == 'hayan',
Member.age == 25))
return " ".join(i.name for i in member_list)
~이면서 ~인 값을 가져온다. and_ 를 먼저 import 해주어야한다!
and_( 조건 ) 으로 사용한다. name이 hayan이면서 age가 25인 데이터를 가져온다.
(9) or
from sqlalchemy import or_
@app.route('/')
def list():
member_list = Member.query.filter(or_(Member.name == 'hayan',
Member.age == 25))
return " ".join(i.name for i in member_list)
마찬가지로 or_ 을 import 해주어야한다. hayan이거나 25살인 데이터를 가져온다.
(10) order by
@app.route('/')
def list():
member_list = Member.query.order_by(Member.age.desc())
return " ".join(i.name for i in member_list)
데이터를 정렬할 때는 filter 함수는 사용하지 않고 order_by를 사용한다.
기본값은 asc() 오름차순이며, desc()는 내림차순이다. age를 내림차순으로 반환한다.
(11) limit
@app.route('/')
def list(limit_num = 5):
if limit_num is None:
limit_num = 5
member_list = Member.query.order_by(Member.age.desc()).limit(limit_num)
return " ".join(i.name for i in member_list)
Query문 실행 결과에서 limit 크기만큼을 반환한다.
즉 위의 코드는 age를 내림차순 한 것에서 5개의 데이터를 반환한다.
(12) offset
@app.route('/')
def list(off_set = 5):
if off_set is None:
off_set = 5
member_list = Member.query.order_by(Member.age.desc()).off_set(off_set)
return " ".join(i.name for i in member_list)
Query문 실행 결과에서 offset 크기만큼 앞에서부터 생략하고 반환한다.
즉 위의 코드는 age를 내림차순한 것에서 앞의 5개를 생략하고 반환한다.
(13) count
@app.route('/')
def list():
member_list = Member.query.order_by(Member.age.desc()).count()
return str(member_list)
Query문 실행 결과로 반환된 tuple수를 반환한다.
age를 내림차순하고 그 튜플들의 개수를 세준다.
'Backend > Flask' 카테고리의 다른 글
Flask 기초 - REST API (2) (Ajax를 사용한 update, delete) (0) | 2022.02.23 |
---|---|
Flask 기초 - REST API (1) (create, read) (0) | 2022.02.23 |
Flask 기초 I - RDB와 Flask 상호작용, 간단한 게시판, Flask JWT (0) | 2022.02.11 |
Flask 기초 I - Blueprint, Jinja2, 로그인 구현, 로깅 (0) | 2022.02.07 |
flask 기초 I - 데이터 화면에 표현, GET, POST 등 (0) | 2022.02.04 |