flask 기초

유동헌·2021년 11월 11일
0

django 말고 처음 접해본 프레임워크이므로, 적응하기가 쉽지 않았다. 가장 애를 먹었었던 점은 django 와는 다르게 파일들이 한 번에 만들어지지 않아 디렉토리 구조를 사용자가 직접 구현을 해야 한다는 것이다. 프로젝트를 한 번 마치고 난 직후여서 지금은 디렉토리 구성에 대한 이해도가 조금은 높아졌으나 난이도가 있는 것은 사실이다. 이 글로 이를 비롯한 flask 의 가장 기초적인 부분을 정리하려고 한다.

flask 디렉토리 구조

A Flask application can be as simple as a single file.

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
    return 'Hello, World!'

https://flask.palletsprojects.com/en/2.0.x/tutorial/layout/

flask documentation 를 보면 아래와 같이 나와있다. flask 는 간단한 파일로 서버까지 구성할 수 있는데, 서비스가 커지면 한 파일로 구성하는 힘들 것이고, 모듈을 이렇게 나눠서 구성해라, 라는 글의 내용이었다. 위의 예시처럼 flask 는 한 파일에 flask 객체를 남고 그 객체의 route, 함수 등을 작성하여 한 파일로 간단하게 서버를 켤 수 있었다. django 와는 확연히 다른 부분이다.

/home/user/Projects/flask-tutorial
├── flaskr/
│   ├── __init__.py
│   ├── db.py
│   ├── schema.sql
│   ├── auth.py
│   ├── blog.py
│   ├── templates/
│   │   ├── base.html
│   │   ├── auth/
│   │   │   ├── login.html
│   │   │   └── register.html
│   │   └── blog/
│   │       ├── create.html
│   │       ├── index.html
│   │       └── update.html
│   └── static/
│       └── style.css
├── tests/
│   ├── conftest.py
│   ├── data.sql
│   ├── test_factory.py
│   ├── test_db.py
│   ├── test_auth.py
│   └── test_blog.py
├── venv/
├── setup.py
└── MANIFEST.in

https://flask.palletsprojects.com/en/2.0.x/tutorial/layout/

# .gitignore

venv/

*.pyc
__pycache__/

instance/

.pytest_cache/
.coverage
htmlcov/

dist/
build/
*.egg-info/

https://flask.palletsprojects.com/en/2.0.x/tutorial/layout/

이번 flask 를 사용한 프로젝트의 경우 이렇게 구성했다. 각각 파일이 어떤 의미를 가지고 있는지 살펴보고, 임포트 관계에 대해서 알아보도록 하자. 필요없어 보이는 것까지, 한 번 살펴본다는 느낌으로 정리해 보겠다.

├── CONVENTION.md
├── Dockerfile
├── PULL_REQUEST_TEMPLATE.md
├── README.md
├── app.py
├── company
│   ├── __init__.py
│   ├── controller.py
│   ├── models.py
│   └── tests.py
├── config.py
├── db_uploader.py
├── requirements.txt
└── temp_data.csv
  • 전체 구조를 파악하는데 중요하지 않은 migrations 폴더와 pycache 폴더는 제하고 살펴본다!
  1. CONVENTION.md, PULL_REQUEST_TEMPLATE.md, README.md : 팀원분들 중에서 현업 경험이 있으신 분들의 의견으로 초기셋팅할 때 아예 코딩 컨벤션을 위한 파일과 풀 리퀘스트 템플릿을 만들어 진행했다. 코딩 컨벤션 때문에 혼란이 가중될 상황을 줄이고, 조금 더 깔끔한 코드 구성을 위해 꼭 필요한 작업 같다.
  2. Dockerfile : docker를 이용해 배포하기 위한 설정 파일들이다.
  3. requirements.txt : 동일한 개발 환경 구성을 위한 파일. 패키지 설치를 위한 파일이다.
  4. app.py : 가장 중요한 파일이다. 이 파일에 대해서 알아보는 것이 이 글의 작성 목적이기도 하다. python의 manage.py 같은 파일인 것 같은데, django를 사용할 때와는 달리, manage.py를 작성하는 것처럼 app.py를 작성해야 한다. 서버도 키고, db에 대한 설정도 넣고.. 그런 일을 한다. 인터넷을 찾아보니 main.py라고 만드시는 분들도 있는 것 같다.
  5. 이번 프로젝트 때는 company라는 폴더를 만들어 관리했다. 그 폴더 안에 시스템 구동에 필요한 기초적인 파일들을 모두 구성했다.
  6. company/init.py : 실행 파일. 잘 모름.
  7. company/controller.py : django의 views.py에 해당하는 파일이다. 서비스에서 정의한 models.py에 따라 CRUD를 진행하는 곳이라고 할 수 있다.
  8. company/models.py : 데이터 스키마를 정의하는 곳
  9. company/tests.py : 테스트 코드가 실행되는 곳
  10. config.py : 설정 값 저장
  11. db_uploader.py, temp_data.csv : 디비 업로드를 위한 파일

디렉토리 구조 상세

  • 가장 중요한 연결 고리. app.py에 설정 값을 적어둔다.
  • 데이터들이 들어있는 건 파일을 따로 database.py 로 따로 구성하는 것이 직관적일 것 같다.

가장 중요한 app.py

from flask              import Flask
from flask_restful      import Api
from flask_migrate      import Migrate

from company.models     import db
from company.controller import CompanyList, GetDetailCompany, CompanyCreateView
from config             import DB_URL

app = Flask(__name__)
api = Api(app)

app.config["SQLALCHEMY_DATABASE_URI"]        = DB_URL
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config["SQLALCHEMY_COMMIT_ON_TEARDOWN"]  = True

db.init_app(app)
db.app = app
db.create_all()
migrate = Migrate(app, db)

api.add_resource(CompanyList, "/search")
api.add_resource(GetDetailCompany, "/companies/<comp_name>")
api.add_resource(CompanyCreateView, '/companies')

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000, debug=False)

flask app 관련

from flask_restful      import Api
from flask_migrate      import Migrate

db를 다룰 시 db migrate를 위해 flask_migrate를 설치하고 Migrate를 임포트해준다.

Flask-RESTful, API를 만들 수 있는 Flask의 확장판. 둘 다 설치를 해야한다.

from flask   import Flask
app = Flask(__name__)

flask 모듈을 사용할 수 있도록 임포트한다.

app 이라는 변수에 Flask() 를 넘겨 app 전역객체로 사용할 수 있게 한다. (인스턴스를 생성한다)

간단하게 이야기하면 Flask 객체를 선언하고, app이라는 변수에 저장하는 것이다. Flask의 파라미터로는 __**name**__ 을 넣어주는데 이는 아래와 같은 역할을 한다고 한다.

__name__ 은 파이썬에서 내부적으로 사용하는 특별한 변수 입니다. 보통 __name__ 의 값을 출력 하면 모듈의 이름을 뜻하는데 만약 실행이 되는 .py 모듈은 __main__ 으로 나옵니다.
Flask app에서는 시스템에서 경로를 설정하기 위한 위치(리소스를 찾는데 사용)를 알기 위해 사용 합니다. 또 디버깅 정보등에도 사용 됩니다.
단일 모듈을 사용 할 때는 따로 지정 하지 않고 __name__ 을 사용 하면 되지만 패키지 형태로 사용 할 경우 패키지 이름을 직접 써줘야 합니다.
단일 모듈: app = Flask(name)
패키지 형태: app = Flask('application 명 지정')

https://wings2pc.tistory.com/entry/웹-앱프로그래밍-파이썬-플라스크Python-Flask

flask가 담긴 객체를 다시 Api 객체에 담아 변수와 진행

일단 패키지 형태로까지 사용하는 방법은 모르니, 넘어가기로 한다.

api = Api(app)

Flask가 담긴 객체 App 객체를 Api 객체에 담는다. 그리고 api라는 변수에 저장한다.

🌀 이 부분 잘 모르겠다. 통신을 위해?

database 관련 설정

app.config["SQLALCHEMY_DATABASE_URI"]        = DB_URL
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config["SQLALCHEMY_COMMIT_ON_TEARDOWN"]  = True

🌀 config 역시 app에서 지원하는 값인지 명확하지 않다.

Flask 는 데이터베이스 기능을 내장하고 있지 않기 때문에 적절한 데이터 베이스를 매칭시켜야 한다고 한다. 또한 app 객체에 몇 가지 설정을 추가해야 한다. 물론 그 전에 flask에서 사용할 데이터 베이스 SQLAlchemy를 설치해야 한다. 위에서 보는 것은 app.py 에 있는 DB에 대한 설정 값이다. 앞에서 언급한 것처럼 database.py 파일을 만들어 따로 관리하는 것이 좋겠다.

데이터베이스를 설치하고 URL을 적어줘야 하는데 저 값에는 db의 비밀번호와 그런 것들이 포함되어 있다.

config.py 파일을 살펴보면,

DB_URL = "mysql+pymysql://[괄호입력x,db이름]:[괄호입력x,비밀번호]@localhost:3306/[db이름]"

이런 식으로 저장이 되어 있고 이 값을 임포트해서 사용하였다.

app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False

이 부분은 추가적인 메모리를 필요로 하므로 False 값으로 두는 것이 좋다고 한다.

app.config["SQLALCHEMY_COMMIT_ON_TEARDOWN"]  = True

커밋 내용을 자동으로 지워주는 것인가? 어떤 의미일까? app.config란 임포트를 하면 자동으로 생기는 부분일까?

# app.py
db.init_app(app)
db.app = app
db.create_all()
migrate = Migrate(app, db)

위의 코드를 이해하기 전에 먼저 models.py를 살펴보자. 우선 첫 번째 프로젝트여서 코드 위치가 조금 어색하다는 걸 알 수 있었다. db = SQLAlchemy() 을 이번에는 models.py에다가 생성했는데 다음 번엔 database 관련 모듈로 묶어야겠다. (flask 공식 문서를 보니 이렇게 하는 방법도 맞는 것 같다! 아래와 같은 내용을 찾을 수 있는데, 사용 방식에서 차이가 있는 것 같다!)

# models.py
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

다시 윗 부분을 보면, db.init_app(app) 이라는 코드를 볼 수 있다. 공식 문서에 따르는 2번째 방법을 사용하면 init을 선언해주고, 지워주고, 이런 코드를 따로 써줘야 한다고 한다. migrate도 따로 설치하고 import 해줘야 한다.

if name == "main":

이 부분에 대한 내용은 아래 링크에서 가져와보았다.

 에서도 name이 나오는데 보통 파이썬에서 메인에 해당 하는 코드에서 많이 볼수 있습니다. 다른 언어에서 main 엔트리 포인트로 표헌이 되며 파이썬에서도 python app.py 로 실행이 되면 app.py 의 코드는 엔트리 포인트가 되어 name 의 값은 main이 됩니다. 즉 프로그램의 시작점이라고 볼수 있습니다.
여기서도 우리는 python app.py 로 실행 시키기 때문에 namemain 이 들어가므로 app.run()이 실행이 되는 것을 알수 있습니다. 만약 app.py 을 외부 모듈로 사용 되는 경우면 name 은 app이라는 이름으로 나오게 되어 app.run() 은 실행이 되지 않습니다.

https://wings2pc.tistory.com/entry/웹-앱프로그래밍-파이썬-플라스크Python-Flask

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000, debug=False)

localhost 주소와 포트번호는 배포를 위해 저렇게 설정했다. api.add_resource(CompanyList, "/search") 이 부분은 url를 나타내는 부분이다

api.add_resource 관련

  • 참고 자료

https://stackoverflow.com/questions/45094636/what-does-endpoint-mean-in-flask-restful

https://flask-restful.readthedocs.io/en/latest/api.html

flask-restfreme으로 이어지는 건가?

💡 dockerfile, [models.py](http://models.py), [controller.py](http://controller.py) 등은 따로 정리할 것이다. dockerfile의 경우 docker를 따로 정리할 것이고 models.py controller.py는 SQLAlchemy와 연동이 되기 때문에 따로 정리할 예정이다.

디렉토리 구조에서 생각해 봐야할 부분

https://if1live.github.io/posts/flask-project-structure/

이 분의 글을 읽고 많은 생각을 하게 되었다. 아는 만큼 쓸 수 있다고, Flask app이 존재하는 파일을 따로 나누고, 서버 실행과 독립된 기능한 하는 파일들은 django에서 영감을 얻어 manage.py라는 파일에 따로 관리를 해두신다고 한다.

References

https://flask.palletsprojects.com/en/2.0.x/tutorial/layout/ : 사진 및 뭐 참고하였습니다.

https://wings2pc.tistory.com/entry/웹-앱프로그래밍-파이썬-플라스크Python-Flask : 기본 구조에 대한 흐름 파악에 많은 도움이 되었습니다. 해당 블로그의 내용을 그대로 인용하기 보다는 읽으며 제 식으로 해석해 블로그를 작성하였습니다. 인용한 부분은 인용으로 처리하였습니다!

https://justkode.kr/python/flask-restapi-1 : 위와 비슷한 내용으로 참고

https://opentutorials.org/module/3669/22070

profile
지뢰찾기 개발자

0개의 댓글