치악산 복숭아

[엘리스 AI트랙] 07-04 Flask 기초 2 본문

elice/토끼성장일지

[엘리스 AI트랙] 07-04 Flask 기초 2

Juliie 2021. 11. 11. 23:02

1. 데이터베이스

  • 데이터를 저장하는 공간
  • 관계형 데이터베이스(RDB)와 NoSQL(Not Only SQL)로 나뉘어져 있음

 

관계형 데이터베이스(RDB)

  • 키(key)와 값(value)들의 간단한 관계를 테이블화 시킨 데이터베이스
  • DML을 사용해서 데이터 간 결합, 제약조건 등의 설정을 통해 데이터를 추출할 수 있음
  • 테이블 간의 데이터 관계를 설정할 수 있음
  • 각 컬럼마다 데이터의 형태가 동일, 정형화된 데이터를 가짐
  • SQL 질의어(쿼리)를 사용

 

클라이언트와 서버 사이에서 일어나는 일


2. Flask와DB 연동하기

 

순서

1) SQL import 하기
2) 데이터베이스 연결하기 con = sqlite3.connect("database.db")
3) 데이터를 불러올 수 있는 cursor 객체 만들기 cur = con.cursor()
4) 실행할 쿼리 작성하기  cur.execute(f"SELECT * FROM Board WHERE name='{result}' or context='{result}'")
5) fetch all 함수 실행(레코드를 배열 형식으로 저장)  rows = cur.fetchall()
6) 데이터베이스 연결 해제  con.close()

 

con = sqlite3.connect('database.db')
con.execute('쿼리문')
con.commit() #DB에 반영
con.close()

# 또는

with sqlite3.connect("database.db") as con:
   con.execute("쿼리문")
   con.commit()

 


3. JWT(JSON Web Token)

  • 웹 표준으로써 두 개체에서 JSON 객체를 사용하여 통신
  • JSON 포맷을 이용하여 사용자에 대한 속성을 저장하는 Web Token
  • 토큰 자체를 정보로 사용하는 Self-Contained 방식으로 정보를 안정적으로 전달
  • 서버와 클라이언트 간의 인증을 도와주는 도구 중 하나

 

JWT의 형태

  • Header: 토큰의 타입과 알고리즘 저장
  • Payload: 토큰에서 사용할 정보(클레임, Claim)를 넣음
    • 토큰 발급자, 토큰 제목, 대상자, exp(만료 시간), iat(발급된 시간), jti(고유 식별자, 토큰의 중복성 방지) 등
  • Signature: 헤더의 정보와 인코딩 값들과 관련된 비밀키가 들어 있음
    • 토큰을 인코딩하거나 유효성 검증을 할 때 사용하는 고유한 암호화 코드

 

  • JSON 형태인 각 부분은 Base64로 인코딩되어 표현됨
  • 각각의 부분을 이어주기 위해 . 구분자 사용

예시

import jwt # PyJWT 모듈 import

data_to_encode = {"name": "elice"} # jwt로 암호화 할 데이터
encryption_secret = "secrete" # jwt 모듈이 사용되는 곳을 특정하기 위해 비밀키를 넣어줌
algorithm = "HS256" # 암호화 알고리즘

encoded = jwt.encode(data_to_encode, encryption_secret, algorithm=algorithm)
decoded = jwt.decode(encoded, encryption_secret, algorithm=[algorithm])

 


4. ORM(Object Relational Mapping, 객체 관계 매핑)

  • 데이터베이스에 객체를 통해 접근하는 방법
  • SQL 쿼리가 없어도 데이터베이스를 다룰 수 있도록 해줌
  • 테이블 구조가 변경될 때 ORM 모델만 수정하면 됨
  • 코드로 작성하기 때문에 쿼리를 직관적으로 이해 가능

# SQL 쿼리문
INSERT INTO 엘리스 (멤버, 나이) VALUES ('여왕', '18');
# ORM

class Members(db.Model): #db.Model은 SQLAlchemy 패키지 안에 들어가 있음 
	__tablename__ = 'my_user' # 데이터베이스 테이블을 명시
    # 데이터베이스 테이블의 컬럼을 명시, `어떤 형태의 데이터를 저장할 것인가`
    id = db.Column(db.Integer, primary_key=True, nullable=False)
    name = db.Column(db.String(20), nullable=False)
    age = db.Column(db.Integer, nullable=False)
    
member1 = Member() # DB의 테이블과 매핑되는 클래스를 모델이라고 함
member1.name = '여왕'
member1.age = '18'
# 또는 아래와 같이 한줄로 작성할 수 있음
member1 = Member(name='여왕', age='18')

db.session.add(member1)
db.session.commit()

 

  • db.session.query(Members)와 Members.query는 같은 의미(전자가 더 명시적)

 


5. SQL Alchemy

  • ORM을 쓸 수 있도록 도와주는 파이썬 라이브러리
  • 파이썬 코드에서 Database와 연결하기 위해 사용할 수 있는 라이브러리

 

Query - CRUD 예제

  • db.session.commit: 데이터베이스에 수정사항을 반영할 것

 

1) Create

  • db.session.add: 내가 만든 변수들을 테이블 안에 넣어줄 것

 

2) Read

  • Members 모델의 쿼리를 사용할 것
  • all()을 붙이면 list 형태로 데이터가 반환됨, 한개여도 리스트
  • first() 제일 처음거 하나, 반환되는 객체는 Model(class)

 

3) Update

  • 해당하는 데이터를 먼저 가져온(Read) 뒤 수정함

 

4) Delete

  • 해당하는 데이터를 먼저 가져온(Read) 뒤 삭제함

 

Query 사용법 예시

1) equal

@app.route('/')
def list():
	member_list = Member.query.filter(Member.name == 'Elice')
    return " ".join(i.name for i in member_list)

2) not equal

@app.route('/')
def list():
	member_list = Member.query.filter(Member.name != 'Elice')
    return " ".join(i.name for i in member_list)

3) like

@app.route('/')
def list():
	member_list = Member.query.filter(Member.name.like('%Elice%'))
    return " ".join(i.name for i in member_list)

4) in

@app.route('/')
def list():
	member_list = Member.query.filter(Member.name.in_(['Elice', 'Dodo']))
    return " ".join(i.name for i in member_list)

5) not in

@app.route('/')
def list():
	member_list = Member.query.filter(~Member.name.in_(['Elice', 'Dodo']))
    return " ".join(i.name for i in member_list)

6) is null

@app.route('/')
def list():
	member_list = Member.query.filter(Member.name == None)
    return " ".join(i.name for i in member_list)
  • Null을 None으로 표현

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)

8)and

from sqlalchemy import and_
@app.route('/')
def list():
	member_list = Member.query.filter(and_(Member.name == 'Elice',
    								Member.age == '15'))
    return " ".join(i.name for i in member_list)
  • db.session.query(Member).filter(A, B, C) 도 가능한 방법

9)or

from sqlalchemy import or_
@app.route('/')
def list():
	member_list = Member.query.filter(or_(Member.name == 'Elice',
    								Member.age == '15'))
    return " ".join(i.name for i in member_list)

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)

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)

12) offset

@app.route('/')
def list(off_set = 5):
	if off_set is None:
    		off_set = 5
    # offset 크기만큼 앞에서부터 생력하고 반환
	member_list = Member.query.order_by(Member.age.desc()).off_set(off_set)
    return " ".join(i.name for i in member_list)

13) count

@app.route('/')
def list():
	member_list = Member.query.order_by(Member.age.desc()).count()
    return str(member_list)
  • 쿼리문 실행결과로 반환된 tuple 수를 반환

 


6. REST API

  • REST: 자원을 이름으로 구분하여 해당 자원의 상태를 주고받는 모든 것
    • 자원(resource)의 표현(representation)에 의한 상태 전달

 

REST의 구성

  • 자원: URI에 표현이 되어야 함 ➡️ 무엇을 서버에 요청할 것인지
  • 행위: HTTP Method ➡️ 어떻게(어떤 방법을) 요청할 것인지
  • 표현: Representations ➡️ API만 보고 무엇을 요청할 것인지 알 수 있도록

 

* URL과 URI의 차이

URL: http://nyamnyamexample.com/index.html

URI: http://nyamnyamexample.com/index 

URL은 실제로 서버 폴더 내에 파일이 있지만 URI는 그렇지 않음(실제로 파일 존재 X)

 

 

REST API 디자인 가이드

1) URI는 자원을 표현해야 함

2) 자원에 대한 행위는 HTTP Method로 나타내야 함(HTTP Method는 Rest API에서 동작을 표현하는 방법)

  • GET: 리소스를 조회
  • POST: 요청된 리소스를 생성
  • PUT: 리소스를 업데이트
  • DELETE: 리소스를 삭제

 

REST API 디자인 예시

  • 리소스 요청은 주로 동사보다는 명사를 사용
    • GET/members/insert/10 보다는 POST/members/10 
    • GET/members/delete/1 보다는 DELETE/members/1 등등
  • 슬래시(/)는 계층 관계를 나타냄
    • http://elice.example.co.kr/lecture/python
  • 파일 확장자는 URI에 포함하지 않음
  • 긴 URI에서는 밑줄(_)보다는 하이픈(-)을 사용
    • http://elice.example.co.kr/board/free-talk

 

HTTP 응답 상태(HTTP status) 코드

상태 코드 내용
200 정상적으로 수행
201 성공적으로 리소스 생성
400 클라이언트의 요청이 부적절할 때
401 인증되지 않은 상태에서 리소스 요청
404 응답하고 싶지 않은 리소스, 혹은 없는 리소스를 요청
ex) Page Not Found
500 서버에 문제가 생겼을 때
Comments