django
말고 처음 접해본 프레임워크이므로, 적응하기가 쉽지 않았다. 가장 애를 먹었었던 점은 django
와는 다르게 파일들이 한 번에 만들어지지 않아 디렉토리 구조를 사용자가 직접 구현을 해야 한다는 것이다. 프로젝트를 한 번 마치고 난 직후여서 지금은 디렉토리 구성에 대한 이해도가 조금은 높아졌으나 난이도가 있는 것은 사실이다. 이 글로 이를 비롯한 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!'
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
# .gitignore
venv/
*.pyc
__pycache__/
instance/
.pytest_cache/
.coverage
htmlcov/
dist/
build/
*.egg-info/
이번 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
database.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)
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
일단 패키지 형태로까지 사용하는 방법은 모르니, 넘어가기로 한다.
api = Api(app)
Flask가 담긴 객체 App 객체를 Api 객체에 담는다. 그리고 api라는 변수에 저장한다.
🌀 이 부분 잘 모르겠다. 통신을 위해?
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 해줘야 한다.
이 부분에 대한 내용은 아래 링크에서 가져와보았다.
④ 에서도 name이 나오는데 보통 파이썬에서 메인에 해당 하는 코드에서 많이 볼수 있습니다. 다른 언어에서 main 엔트리 포인트로 표헌이 되며 파이썬에서도 python app.py 로 실행이 되면 app.py 의 코드는 엔트리 포인트가 되어 name 의 값은 main이 됩니다. 즉 프로그램의 시작점이라고 볼수 있습니다.
여기서도 우리는 python app.py 로 실행 시키기 때문에 name은 main 이 들어가므로 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를 나타내는 부분이다
https://stackoverflow.com/questions/45094636/what-does-endpoint-mean-in-flask-restful
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라는 파일에 따로 관리를 해두신다고 한다.
https://flask.palletsprojects.com/en/2.0.x/tutorial/layout/ : 사진 및 뭐 참고하였습니다.
https://wings2pc.tistory.com/entry/웹-앱프로그래밍-파이썬-플라스크Python-Flask : 기본 구조에 대한 흐름 파악에 많은 도움이 되었습니다. 해당 블로그의 내용을 그대로 인용하기 보다는 읽으며 제 식으로 해석해 블로그를 작성하였습니다. 인용한 부분은 인용으로 처리하였습니다!
https://justkode.kr/python/flask-restapi-1 : 위와 비슷한 내용으로 참고