728x90

먼저, 데이터베이스의 연결 정보를 저장할 파일을 만들어야 한다. 그리고 다음처럼 데이터베이스 연결 정보를 저장한다.

(config.py)

db = {
    "user": "root",
    "password": "1234",
    "host": "localhost",    #1
    "port": 3306,           #2
    "database": "minister"  #3
}
DB_URL = f"mysql+mysqlconnector://{db['user']}:{db['password']}@
{db['host']}:{db['port']}/{db['database']}?charset=utf8"

 

1. 접속할 db의 주소다. 만일 외부 서버에 설치되어있는 데이터베이스에 접속한다면 해당 서버의 주소를 지정해 주어야 한다.

2. 접속한 db의 포트 넘버다. 관계형 데이터베이스는 주로 3306 포트를 통해 연결된다. api나 사이트와 마찬가지로 데이터베이스도 네트워크를 통해 연결되는 시스템이므로 당연히 포트 정보가 필요하다.

 

3. 실제 사용할 db 이름. 이전에 minister란 db 이름으로 테이블을 생성했다. 테이블 만드는 법을 모른다면 내 블로그 카테고리 mysql에 있는 내용을 참고!

 

( 이렇게 설정 파일을 따로 만드는 이유는 두가지 인데, 1. 설정 정보를 따로 관리함으로써 민감한 개인 접속 정보를 노출하지 않아도 된다. 2. 각 환경과 설정에 맞는 설정 파일을 적용할 수 있게 된다.

 

 

 

 

 

 

 

 

 

 

app.py을 수정해 config.py 파일에서 데이터베이스 설정 정보를 읽어들여 데이터베이스와 연결하도록 한다. 

sqlalchemy 를 사용해 mysql 데이터베이스에 연결해 데이터를 저장 및 읽어들이도록 한다.

from flask import Flask , jsonify, request
from sqlalchemy import create_engine, text


# config 파일에서 데이터베이스 설정 정보 읽어들여 db와 연결
def create_app(test_config = None):   #1
    app = Flask(__name__)

    if test_config is None:                   #2
        app.config.from_pyfile("config.py")
    else:
        app.config.update(test_config)

	#3
    database = create_engine(app.config["DB_URL"], encoding="utf-8", max_overflow=0)
    app.database = database   #4
    return app  

 

1. 함수 정의. create_app 함수가 test_config 인자를 받는다. 단위 테스트를 실행시킬 때 테스트용 데이터베이스 등의 테스트 설정 정보를 적용하기 위함이다. 

 

2. 만일 인자가 none 이면 config 파일에서 설정을 읽어들인다. 아니라면, test_config 값이 설정되어 들어왔다면 test_config 의 설정을 적용시킨다.

 

3. 위에서 생성한 Engine 객체를 flask 객체에 저장함으로써 create_app 함수 외부에서도 데이터베이스를 쓸 수 있게 한다.

 

 

 

 

 

 

 

회원가입 엔드포인트

    
    
    
    @app.route("/sign-up", methods=["POST"])  
    def sign_up():
        new_user = request.json
        new_user_id = app.database.execute(text("""   #1
        INSERT INTO users(
            name,
            email,
            profile,
            hashed_password
        ) VALUES (
            :name,
            :email,
            :profile,
            :password
        )
        """), new_user). lastrowid        #2

row = current_app.database.execute(text("""
    SELECT
        id,
        name,
        email,
        profile
    FROM users
    WHERE id = :user_id
    """), {
        'user_id' = :new_user_id
    }).fetchone()

    created_user = {
        'id'     :row['id'],
        'name'   :row['name']
        'email'  :row['row']
        'profile':row['profile']
    } if row else None

    return jsonify(created_user)

http 요청을 통해 전달받은 정볼르 db에 저장한다. 

app.database는 SQLAlchemy 는 mysql 에 연결된 Engine 객체다. 

app.database 를 통해 원하는 구문을 해당 데이터베이스에 실행하게 된다. 

 

, newuser). lastrowid ==> sql 구문에 사용될 실제 데이터들은 http 요청에서 읽어들인 데이터를 그대로 사용한다. http  요청을 통해 전송된 JSON데이터의 구조가 SQL에서 필요한 필드를 모두 포함하고 있기 때문이다. 

만일 필드 이름이 틀리거나 필드가 부재인 경우 오류가 나게 된다. 새로 사용자가 생성되면, 새로 생성된 사용자의 id 를 lastrowid 를 통해 읽어 들인다.

 

 

 

 

 

 

FLASK 환경을 실행 시키고

 

 

 

코딩한 내용대로 http 요청을 보내면 위와 같이 데이터가 전송된 것을 확인할 수 있다.

 

 

같은 방법으로 나머지 엔드포인트들도 구성하면 끝 !

728x90

SQLAlchemy : 파이썬 코드에서 DB 와 연결하기 위해 사용하는 라이브러리 중 하나.

ORM (관계형 DB 테이블들을 프로그래밍 언어의 클래스로 표현할 수 있게 해주는 것.

           즉, 클래스를 사용해 테이블을 ㅠㅛ현하고 데이터를 저장,읽기,업데이트 등을 할 수 있게 해준다.)

 

파이썬 가상환경을 활성화한 후 pip 명령어를 이용해 설치해준다.

 

Mysql용 DBAPI 사용하기 위해 공식 파이썬 DBAPI 인 mysql-connector 를 사용한다.

 

 

 

'Language > python' 카테고리의 다른 글

웹 스크래핑 기초 ) 웹툰  (0) 2021.03.24
SQLAlchemy 를 사용하여 api와 database 연결하기  (0) 2021.02.27
Strip(), sep(),zip()  (0) 2021.02.21
주피터로 flask - BeautifulSoup()  (0) 2021.02.17
여러가지 표기법  (0) 2021.02.09
728x90

1. Strip()

Python에서 strip()을 이용하면 문자열에서 특정 문자를 제거할 수 있습니다. Java 등의 다른 언어들도 strip()을 제공하며, 기능은 모두 비슷합니다.

Python의 String은 다음 함수를 제공합니다.

  • strip([chars]) : 인자로 전달된 문자를 String의 왼쪽과 오른쪽에서 제거합니다.
  • lstrip([chars]) : 인자로 전달된 문자를 String의 왼쪽에서 제거합니다.
  • rstrip([chars]) : 인자로 전달된 문자를 String의 오른쪽에서 제거합니다.

인자를 전달하지 않을 수도 있으며, 인자를 전달하지 않으면 String에서 공백을 제거합니다.

 

공백(white space) 제거

다음 코드는 strip()에 인자를 전달하지 않습니다. 인자를 전달하지 않으면 문자열에서 공백을 제거합니다.

text = ' Water boils at 100 degrees ' 

print('[' + text.rstrip() + ']') 

print('[' + text.lstrip() + ']') 

print('[' + text.strip() + ']')

결과

[ Water boils at 100 degrees]

[Water boils at 100 degrees ]

[Water boils at 100 degrees]

동일한 문자 제거

인자로 문자 1개를 전달하면 그 문자와 동일한 것을 모두 제거합니다. 동일하지 않은 문자가 나올 때까지 제거합니다.

text = '0000000Water boils at 100 degrees 000'

print(text.lstrip('0'))

print(text.rstrip('0'))

print(text.strip('0'))

결과

Water boils at 100 degrees 000

0000000Water boils at 100 degrees

Water boils at 100 degrees

여러 문자 제거

인자로 여러 문자를 전달하면 그 문자들과 동일한 것들을 모두 제거합니다. 동일하지 않은 문자가 나올 때까지 제거합니다.

text = ",,,,,123.....water....pp"

print(text.lstrip(',123.p'))

print(text.rstrip(',123.p'))

print(text.strip(',123.p'))

결과

water....pp

,,,,,123.....water

water

 

 

2. sep()

이 옵션을 이용하게 되면 print문의 출력문들 사이에 해당하는 내용을 넣을 수 있습니다. 기본 값으로는 공백이 들어가 있으며 이를 사용해 원하는 문자를 입력할 수 있습니다.

 

print("1-1칸","1-2칸","1-3칸",end = "**end 입니다** \n")
print("2-1칸","2-2칸","2-3칸",sep = "**sep입니다**")

 

 

 

3. zip() : zip() 은 동일한 개수로 이루어진 자료형을 묶어 주는 역할을 하는 함수

 

Number = [1,2,3,4]
Name = ['hong','gil','dong','nim']
Number_Name = list(zip(Number,name))
print(Number_Name)
'''
결과 : [(1 ,'hong'), (2 ,'gil'), (3 ,'dong'), (4 ,'nim')]
'''

-list 아닌 하나의 딕셔너리로 만들 때

 

Number = [1,2,3,4]
Name = ['hong','gil','dong','nim']
dic = {}
for i in range(len(Number)) : 
    dic[Number[i]] = Name[i]
print(dic)
'''
결과 : {1 : 'hong' , 2 : 'gil' , 3 : 'dong' , 4 : 'nim'}
'''
728x90

 

 

 

 

# 모듈을 읽어 들입니다.
from flask import Flask
from urllib import request
from bs4 import BeautifulSoup

# 웹 서버를 생성합니다.
app = Flask(__name__)
@app.route("/")

def hello():
    # urlopen() 함수로 기상청의 전국 날씨를 읽습니다.
    target = request.urlopen("http://www.kma.go.kr/weather/forecast/mid-term-rss3.jsp?stnId=108")

    # BeautifulSoup를 사용해 웹 페이지를 분석합니다.
    soup = BeautifulSoup(target, "html.parser")

    # location 태그를 찾습니다.
    output = ""
    for location in soup.select("location"):
        # 내부의 city, wf, tmn, tmx 태그를 찾아 출력합니다.
        output += "<h3>{}</h3>".format(location.select_one("city").string)
        output += "날씨: {}<br/>".format(location.select_one("wf").string)
        output += "최저/최고 기온: {}/{}"\
            .format(\
                location.select_one("tmn").string,\
                location.select_one("tmx").string\
            )
        output += "<hr/>"
    return output

 

 

728x90

코드 작성 시 자신만의 방법으로 표기를 한다.

예) 클래스는 첫 문자를 대문자, 변수명은 알아 볼 수 있게...

 

하지만 같이 일을 하는 입장에선 서로 법칙을 정하여 프로젝트를 수행하면 훨씬 일의 효율을 높일 수 있다.

프로젝트는 대화가 기본이니, 이런 기본적인 것부터 지켜야 한다.

 

 

1. 카멜 표기법 

 

첫 글자를 대문자로 적되, 맨 앞에 오는 글자는 소문자로 표기하는 것이다.

표기한 모습이 낙타의 등과 같다고 하여 카멜 표기법이라고 부른다. 

 

int totalNumber;

왜? 눈에 잘 띄려고!!

 

 

2. 파스칼 표기법

카멜표기법과 거의 흡사하지만 맨 앞에 오는 글자도 대문자로 표기하는 것이다.

 

int TotalNumber;

 

3. 헝가리안 표기법

접두어에 자료형을 알아볼수 있게끔 표기하는 것이다. (요새는 잘 사용 안함)

예) 문자열은 변수명 앞에 str을 붙인다.

 

String strName;

 

 

4. 스네이크 표기법(Snake Case)

 

단어 사이에 언더바를 넣어서 표기하는 것이다. 

 

int total_number;

 

 

 

 

변수 -> 카멜표기법
클래스 -> 파스칼표기법
함수 -> 스네이크표기법  

 

 

728x90

1. 회원가입

간단히 id, name, email, password, profile 정보를 넣을 것!

 

회원가입 기능을 하는 엔드포인트는

 

 

 

 

1- request : 사용자가 http 요청을 통해 전송한 json 데이터 읽어들이는 기능. jsonify 는 딕셔너리 객체를 json으로 변환해 http 응답으로 보낸다고 한다.

 

8- 예를 들어 naver.com/abc 라는 주소가 있으면 "/sign-up"이 /abc 의 위치라고 이해하면 쉽다. 

 

 

 

그 다음 app.py 파일에 회원가입 엔드포인트를 추가해 터미널에서 정보 입력 시 넘어갈 수 있도록 하자.

 

@app.route("/sign-up", methods=['POST'])
def sign_up():
    new_user               = request.json
    new_user["id"]         = app.id_count
    app.users[app.id_count] = new_user
    app.id_count           = app.id_count + 1

    return jsonify(new_user)

이렇게 함수 그대로 가져와주면 된다.

 

 

 

2. 터미널에서 회원가입 요청 보내기

 

 

FLASK_ENV : Flask 가 실행되는 개발 스테이지. development 는 debug mode 가 실행된다고 한다.

app.py 에서 실행되게 위치 잡아주기.

처음에 파일 이름 다르게 지정해서 계속 삽질함... ㅋ 봐주신 짠님 감사드립니다 ㅠㅠ 

 

 

 

 

정보입력 성공 !

httpie 를 사용해 정보를 보낸건데 엔드포인트 주소 다음에 (sign-up) field=value 형식으로 그냥 쓰기만 하면 된당.

 

 

같은 방식으로 트윗글올리기 작성

 

 

 

 

 

 

 

from flask import jsonify, Flask, request

app = Flask(__name__)
app.users = {}
app.id_count = 1
app.tweet = []

@app.route('/tweet',methods=['POST'])
def tweet():
    payload = request.json
    user_id = int(payload['id'])
    tweet   = payload['tweet']

    if user_id not in app.users:
        return '사용자가 존재하지 않습니다.', 400

    if len(tweet) > 300:
        return '300자를 초과했습니다.', 400

    app.tweet.append({
        'user_id' : user_id,
        'tweet' : tweet
    })

    return '',200

 

위의 방법과 같게 app.py 에 트윝 엔드포인트를 추가해주고,

 

터미널에서 아이디와 트위터 글 한줄 써주고 보내주면 마무리!

728x90

프론트, 백엔드 API 시스템은 일반적으로 HTTP 포로토콜을 기반으로 통신한다. 그러므로 이를 이해하는 것은 필수이다.

 

HTTP: 웹상에서 서로 다른 서버 간에 하이퍼텍스트 문서, HTML 주고받을 수 있도록 만들어진 프로토콜.

현재 공부하고 있는 책에선 서로 다른 나라의 사람들을 위한 공용어에 비유를 했다.

 

HTTP 통신 방식에는 2가지가 있다. 하나는 요청,응답 방식이고 하나는 Stateless 이다.

 

 

1. 요청과 응답

http 를 기반으로 통신할 때 클라이언트가 먼저 http 요청을 서버에 보내면 서버는 요청을 처리한 후 결과에 따른 응답을 클라이언트에 보낸다.

 

2. stateless

말 그대로 상태라는 개념이 없다. 즉 각각의 http 통신은 독립적이며 그 전에 처리된 통신에 대해 알지 못한다. 

단점은, 예로 들면 http 요청 처리를 위해 한 사용자가 로그인이 되어야 한다고 하면, 사용자가 그 전에 로그인을 했더라도 stateless 이기 때문에 새로운 요청을 보낼 때 로그인 사실 여부를 포함시켜서 보내야 한다. 이를 위해 클라이언트가 사용자의 로그인 사실 여부를 기억하고 있어야 한다.

이를 해결하기 위해 쿠기, 세션을 사용한다.

 

 

 

쿠기: 웹 브라우저가 웹사이트에서 보낸 정보 저장할 수 있도록 하는 작은 파일. 

http 는 stateless 이므로 클라이언트에서 모든 정보를 포함해 요청을 보내야 한다. 그러므로 클라이언트가 정보를 저장할 수 있는 메커니즘이 필요한데, 웹 브라우저는 쿠키라고 하는 파일을 사용해 필요한 정보를 저장한다.

 

세션은 쿠키와 마찬가지로 http 통신 상에서 필요한 데이터를 저장할 수 있게 하는 메커니즘이다. 

차이점은 쿠키: 웹 브라우저, (클라이언트에서 데이터 저장)

세션: 웹 서버에서 데이터 저장

 

 

 

 

 

 

 

 

http 요청 구조

start line, Headers, Body

 

start line 

1. http 메소드 : get(서버로부터 어떠한 데이터를 받고자 한다), post(서버에 새로운 데이터를 저장하고자 한다), put, delete ...

 

2. request target : http 요청이 전송되는 목표 주소. (/ping)

 

3. http version 

 

 

headers

http 요청에 대한 정보.

 

host : 요청이 전송되는 target의 호스트의 url 주소 알려줌. 

ex. HOST : google.com 구글에 보내는 http 요청의 포스트 헤더

 

 

user-agent : 요청을 보내는 클라이언트에 대한 정보.

 

 

 

 

 

body

1. status line : 응답 메시지의 상태 간략히 요약해 알려줌.

만약 요청이 정상적으로 처리되었으면 응답의 status code는 200. status text 는 OK.

 

301 Moved Permanently : 요청을 보낸 엔드포인트의 URL 주소가 바뀌었다는 것을 나타냄;

 

 

 

 

 

 

 

 

HTTP 메소드 중 GET, POST 가 많이 쓰이는데 POST는 단순히 데이터만 받아오는 GET 과는 달리 데이터를 생성, 수정, 삭제 요청할 떄 주로 사용된다. 

 

 

OPTIONS는 특정 엔드포인트에서 허용하는 메소드들이 무엇이 있는지 알고자 하는 요청. 

 

 

 

 

728x90

엔드포인트? api 서버가 제공하는 통신 채널 혹은 접점. 

 

프론트엔드 서버 등의 클라이언트가 백엔드 api 서버와 통신할 때 엔드포인트에 접속하는 형태로 통신하게 됨. 

각 엔드포인트는 고유의 URL 주소를 가지게 되고 그 주소를 통해 해당 엔드포인트에 접속할 수 있다. 

 

 

 

각 엔드포인트는 고유의 기능을 담당하고 있다. 이러한 엔드포인트들이 모여서 하나의 API를 구성하는 것이다.

(EX. SNS서비스 API는 사용자 사인업, 로그인, 새로운 포스팅 생성, 친구맺기 등의 여러 엔드포인트로 구성)

 

 

 

Ping 엔드포인트는 단순히 pong 이라는 텍스트를 리턴하는 엔드포인트이다. 이는 주로 api 서버가 운행되는 중인지 정지된 상태인지를 간단히 확인할 때 체크하는 엔드포인트이다.

 

 

 

먼저 api 코드가 위치할 디렉터리 생성하자.

(api) yuz@DESKTOP-UK4R45C:/mnt/c/Users/이유진$ mkdir -p ~/Projects/api

나는 파이썬 안에서 (>>> mkdir~ ) 해서 계속 안됐었는데,

파이썬 나오고 api 실행한 후 해야 한다. ㅠ

 

 

 

 

 

 

 

1. flask 사용하기 위해 flask 클래스 import.

 

3. 임포트한 flask 클래스를 객체화시켜 app 라는 변수에 저장. 이 변수가 API 애플리케이션이다. 

    이 변수에 API 설정과 엔드포인트를 추가하면 API가 완성되는 것.

 

5. Flask route 데코레이터를 사용하여 엔드포인트를 등록한다.

   그 다음에 나오는 ping 함수를 엔드포인트를 함수로 등록 하였으며,

    고유 주소는 ping 이고 HTTP 메소드는 GET 으로     설정되어 등록.

 

7. Ping 함수 정의. route 데코레이터를 통해 엔드포인트로 등록된 함수이다. 

 

 

 

이 파일의 코드에서 집중해야 할 부분은 엔드포인트를 지정하는 방법이다. Flask 에서는 route 데코레이터를 사용해 함수들을 엔드포인트로 등록하는 방식이 사용된다. 즉, Flask 에서 엔드포인트를 구현한다는 것은 결국 일반 함수를 구현하는 것과 큰 차이가 없다는 뜻이다. 

 

 

 http 요청과 응답이 오고가는 구조이다. /ping 주소에 GET 요청을 보내면 응답은 200 Ok 코드오ㅓ 함께 pong 이라는 텍스트를 보내는 것이다. Flask 가 HTTP 부분을 자동으로 처리해 준다.
PING 함수가 단순히 퐁 스트링을 리턴해도 Flask 가 자동으로 http 응답으로 변환시켜 준다. 그러므로 flask 사용하면 개발자는 최대한 일반 함수를 구현하듯 엔드포인트를 구현할 수 있다.

 

 

 

본격적으로 API 실행하기 위해 터미널에

FLASK_APP=app.py FLASK_DEBUG=1 flask run 을 입력한다. 

 

플라스크 앱 환경변수에 Flask 앱을 실행시키는 파일을 지정해준다.(app.py)

지정된 파일이 명령어를 실행시키는 디렉터리에서 찾을 수 있어야 한다.

 

디버그 환경변수를 1로 지정해놓으면 디버그 모드가 활성화된다. 이 모드에서는 코드 수정 시 자동 재시작되어 자동으로 반영된다.

 

 

 

잘 돌아가는지 api 접속해 테스트하기 위해 httpie (터미널 명령어 환경에서 HTTP 요청 보낼 수 있게 해줌.) 명령어를 사용한다.

 

sudo apt install httpie

 

 

설치 후 

 

 

 

 

 

-v : verbose 옵션. 해당 HTTP 요청과 응답에 관한 추가적인 정보를 출력한다.

 

 

FLASK RUN 을 통해 API 실행되고 있는 것을 알 수 있었고, 위를 통해 HTTP 요청에 "pong" 텍스트가 응답으로 왔다. 

ping 엔드포인트가 제대로 실행되는 것을 확인한 것이다.



728x90

flask 는 파이썬으로 웹 애플리케이션을 구현할 때 사용되는 아주 가벼운 웹 프레임워크이다.

api 개발 입문용으로 사용하기 좋다. (나같은 초급자)

 

 

 

이때 프레임워크란, 특정 시스템을 구현하기 위해서 공통적으로 요구되는 기능들, 구조를 재사용이 가능하도록 구현해 놓은 것. 

웹 프레임워크로 예를 들어보면, 모든 웹 시스템은 소켓을 통해 네트워크와 연결해 외부 시스템으로부터 통신을 주고받을 수 있어야 한다. 이러한 기능은 이미 규격화되어 시스템마다 각각 따로 구현할 필요가 없다.

그러므로 flask 같은 웹 프레임워크를 사용함으로써 개발자는 웹 시스템을 통해 제공하고자 하는 비즈니스 로직에만 집중할 수 있는 것이다. 

 

프레임워크와 비슷한 개념 = 라이브러리.

차이점은,

라이브러리 : 개발자가 자신의 코드 안에서 실행한다면,  ( 개발자의 코드 안에 일부분으로 포함되어 개발자가 원하는 대로 사용 가능)

프레임워크 : 프레임워크가 개발자의 코드를 실행. ( 프레임워크가 제공하는 틀 안에서 개발자가 필요한 로직 구현)

 

 

 

이제 Flask 사용해 본격적으로 API 개발을 해보도록 하자! 

 

 

 

콘다를 사용해 파이썬 가상 환경을 설치한 것이다. api 라는 이름은 그냥 내가 정한 것.

중간에 y 할거냐는 질문에 y라고 답하면 계속 설치 된당.

 

 

 

 

 

yuz@DESKTOP-UK4R45C:/mnt/c/Users/이유진$ source activate api
(api) yuz@DESKTOP-UK4R45C:/mnt/c/Users/이유진$

파이썬 가상 환경이 성공적으로 활성화되었다. 

만약 비활성화시키고 싶다면 conda deactivate .

 

 

 

참고로 여러 개의 파이썬 프로젝트를 개발하다 보면 가상 환경의 이름이 생각나지 않을 떄가 있는데, 그럴 때는 

conda env list 명령어 실행해 현재 생성된 가상 환경들 리스트를 확인하면 편리하다.

 

 

 

 

이제 Flask 를 설치해보자. 설치 전에 항상 파이썬 가상 환경을 실행시키는 걸 잊지 말도록 하자.

 

 

 

Flask 는 pip(파이썬의 패키지 매니저) 를 통해 간단히 설치할 수 있다. 이를 사용해 터미널 등의 커맨드라인 환경에서 간단히 원하는 파이썬 패키지들을 설치할 수 있다. 

 

 

 

 

 

 

 

정상적으로 설치되었다면  flask 를 import 해 사용할 수 있어야 한다. 

 

 

 

 

 

잘 설치해줬는지 확인하기 위해

1. python 입력

2.  >>> from flask import Flask 입력
3.  >>> app = Flask("test")   입력했을 때
>>>

이렇게 빈 칸이 뜨면 잘 설치한 것이다.

 

+ Recent posts