플라스크 웹 프레임워크 기본 가이드

1 플라스크 소개

# 현재 파이썬 생태계에서 유명한 웹 프레임워크
    -django: 대규모 프로젝트에 적합한 포괄적인 프레임워크
    -Flask: 경량화된 핵심 기능에 집중한 마이크로 프레임워크
        -다양한 확장 기능을 통해 필요한 기능을 추가할 수 있음
    ----- 동기 프레임워크 ----- django 3.x 버전부터 비동기 프레임워크로 전환
    
    ---- 비동기 프레임워크 --------
    -Tornado: 과거에 주로 사용되었던 비동기 프레임워크
    -Sanic : 파이썬 3.6 이상 버전 지원
    -FastAPI
# Flask
Flask는 파이썬으로 개발되었으며 jinja2 템플릿 엔진과 Werkzeug WSGI 서버에 기반한 마이크로 프레임워크입니다. Werkzeug는 본질적으로 소켓 서버로, HTTP 요청을 수신하고 전처리한 후 플라스크 프레임워크를 호출합니다. 개발자는 플라스크 프레임워크가 제공하는 기능을 사용하여 요청을 처리하고 사용자에게 응답합니다. 복잡한 콘텐츠를 반환해야 할 경우 jinja2 템플릿을 사용하여 템플릿과 데이터를 렌더링하고, 렌더링된 문자열을 사용자 브라우저로 반환합니다.

"마이크로"(micro)라는 용어는 전체 웹 애플리케이션을 단일 파이썬 파일에 넣어야 한다는 의미가 아니며(물론 가능은 합니다), 기능적으로 부족하다는 의미도 아닙니다. 마이크로 프레임워크에서 "마이크로"라는 것은 플라스크가 핵심을 단순하고 확장하기 쉽게 유지하려는 의미입니다. 플라스크는 사용자를 대신해 많은 결정을 내리지 않습니다 - 예를 들어 어떤 데이터베이스를 사용할지와 같은 결정은 사용자가 직접 내립니다. 플라스크가 선택한 기능 - 예를 들어 템플릿 엔진 -은 쉽게 교체할 수 있습니다. 나머지 모든 것은 사용자의 통제하에 있습니다. 이렇게 하여 플라스크는 사용자와 완벽하게 조화를 이룰 수 있습니다.

기본적으로 플라스크는 데이터베이스 추상 계층, 폼 검증, 기타 다양한 라이브러리로 대체 가능한 기능을 포함하지 않습니다. 그러나 플라스크는 확장 기능을 통해 이러한 기능을 애플리케이션에 추가할 수 있으며, 마치 플라스크 자체가 구현한 것처럼 작동합니다. 수많은 확장 기능은 데이터베이스 통합, 폼 검증, 업로드 처리, 다양한 오픈 인증 기술 등의 기능을 제공합니다. 플라스크는 "작을" 수 있지만, 복잡한 요구사항이 있는 프로덕션 환경에서 사용할 준비가 되어 있습니다

2 플라스크 빠른 시작

# pip3 install flask     # 최신 버전 2.2.2


from flask import Flask

app = Flask(__name__)

# 라우트 등록
@app.route('/home')
def welcome():
    return '안녕하세요!'


if __name__ == '__main__':
    app.run(host='127.0.0.1',port=5000)

3 설정 파일 작성법

# 프로젝트 설정 파일: 설정하지 않으면 기본값이 적용됨
# 중요한 설정들
# DEBUG: 디버그 모드 여부
# SECRET_KEY: 프로젝트의 비밀 키
# print(app.config)
#   1 설정 방법 중 하나: (작은 스크립트 테스트 단계에서 사용) app 객체를 직접 설정, 몇 가지만 설정 가능, 본질적으로 모두 app.config에 저장됨
# app.debug=True
# app.secret_key='securekey123'
# app.session_cookie_name='mysession'
# print(app.config)

# 2 app.config를 통한 직접 설정
# app.config['DEBUG'] = True
# app.config['SECRET_KEY'] = 'mysecretkey'
# print(app.config)

# 3 설정 파일 사용 (django와 유사), 덜 사용됨
# app.config.from_pyfile('config.py')
# print(app.config)

# 4 클래스를 통한 설정 (많이 사용됨, 여러 환경 설정 가능)
# app.config.from_object('config.DevelopmentConfig')
# app.config.from_object('config.ProductionConfig')
# print(app.config)

# 5 아래 내용은 참고용
# app.config.from_envvar("환경 변수 이름")
# app.config.from_json("json 파일 이름")

# 분산 설정 센터 사용
import requests
res=requests.get('http://config-server/api/config').json()
app.config.from_mapping(res)
# 확장: 모든 설정 파일을 로컬에 저장

4 라우팅 시스템

# 플라스크의 라우팅 시스템은 django의 urls.py와 달리 데코레이터 형식을 사용합니다

# 사용 방법
@app.route: 중요한 파라미터
    -rule: 문자열 경로, 변환기 사용 <string:name> <name>
        'default':          UnicodeConverter,
        'string':           UnicodeConverter,
        'any':              AnyConverter,
        'path':             PathConverter,    # /경로/서브경로/
        'int':              IntegerConverter, # 정수
        'float':            FloatConverter,   #실수
        'uuid':             UUIDConverter,    #uuid-형식-식별자
        #주의: string, int, path 변환기
    -methods: 리스트, 허용할 HTTP 메서드 지정, 리스트에 없는 메서드는 지원되지 않음
    -endpoint: 라우트 별칭, 지정하지 않으면 데코레이터가 적용된 함수명이 별칭으로 사용됨, django의 name과 동일

5 라우팅의 본질

    def route(self, rule, **options):
        def decorator(f):
            endpoint = options.pop("endpoint", None)
            self.add_url_rule(rule, endpoint, f, **options)
            return f

        return decorator
# 플라스크에서 라우팅은 데코레이터를 사용하지만, 실제로는 app 객체(Flask)의 메서드인 self.add_url_rule를 호출하는 것입니다

# 뷰 함수에 데코레이터를 사용하는 것은 실제로 self.add_url_rule를 호출하는 것과 동일합니다
    #데코레이터 없이 이 메서드를 직접 호출하여 라우트를 등록할 수도 있습니다
    
# 라우팅의 본질:
'''
1 @app.route('/')가 먼저 실행되어 데코레이터 내부 함수를 반환합니다
    @decorator
    def index():
2 index=decorator(index)가 실행됩니다
    def decorator(f):
        # @app.route('/',endpoint='index') endpoint가 전달되지 않으면 None이 됩니다
        endpoint = options.pop("endpoint", None)
        # self는 Flask 객체, app: rule은 경로, endpoint는 별칭이며 None이고 나머지는 메서드 등으로 전달됩니다
        self.add_url_rule(rule, endpoint, f, **options)
        return f
3 데코레이터가 적용된 후에도 원래 함수가 반환되지만, self.add_url_rule가 실행됩니다

4 Flask 클래스의 add_url_rule 메서드
    -rule: 데코레이터에 전달된 경로
    -endpoint: 별칭
    -view_func: 뷰 함수 (괄호 없이)
    
5 결론: 더 이상 데코레이터를 사용하지 않고 직접 라우트를 등록할 수 있습니다
    
    app.add_url_rule('/about', view_func=about_page, endpoint='about')
    
'''


# 실제로 django와 큰 차이는 없으며, 단지 데코레이터를 사용하여 구성할 뿐입니다

5.1 add_url_rule 파라미터

@app.route와 app.add_url_rule 파라미터:
# rule, URL 규칙
# view_func, 뷰 함수 이름
# defaults = None, 기본값, URL에 파라미터가 없지만 함수에는 파라미터가 필요할 때 사용
{'k': 'v'} 형식으로 함수에 파라미터를 제공, django의 kwargs와 유사

# endpoint = None, 이름, URL 역생성에 사용, 즉: url_for('이름'), django의 reverse와 동일
# methods = None, 허용되는 HTTP 메서드, 예: ["GET", "POST"]

# strict_slashes URL 마지막 / 기호에 대한 엄격한 요구
strict_slashes = None
    '''
        @app.route('/home', strict_slashes=False)
        #http://www.example.com/home/ 또는 http://www.example.com/home 모두 접근 가능
        @app.route('/home', strict_slashes=True)
        #http://www.example.com/home만 접근 가능
    '''
# redirect_to 지정된 주소로 리디렉션
redirect_to = None, 
    '''
        @app.route('/user/<int:user_id>', redirect_to='/profile/<user_id>')
    '''

6 클래스 기반 뷰(CBV) 작성법

6.1 플라스크의 CBV 작성법

# 첫 번째: MethodView를 상속받는 클래스 작성
    class LoginView(MethodView):
        def get(self):
            return 'GET 요청 처리'
        def post(self):
            return 'POST 요청 처리'
        
# 두 번째: 라우트 등록 name은 별칭(실제로는 endpoint)
    app.add_url_rule('/signin', view_func=LoginView.as_view(name='login'))
    
# 세 번째: /signin으로 GET 요청을 보내면 LoginView의 get 메서드가 실행됩니다

6.2 CBV에 데코레이터 추가

# 첫 번째 문제점: CBV에 데코레이터를 추가하는 방법?
    클래스 속성에 decorators = [auth_decorator, ]를 추가합니다. 이 속성은 리스트이며, 리스트 순서대로 각 메서드에 데코레이터가 적용됩니다
    
     def as_view(cls, name, *class_args, **class_kwargs ) :
       ....
       if cls.decorators:
          for decorator in cls.decorators:
            '''
            # 데코레이터 원리:
             @auth_decorator
             def view():
             실제로는 view=auth_decorator(view)  
            '''
            # view에 데코레이터 적용 ----> 뷰 클래스의 메서드에 데코레이터 적용
             view = decorator(view) 
        return view

6.3 as_view 실행 흐름

# 두 번째 문제점: as_view의 실행 흐름
    def as_view(cls, name, *class_args, **class_kwargs):
        def view(**kwargs):
            return self.dispatch_request(**kwargs)
        return view
 
    -요청이 오고 라우트가 매칭되면 as_view 내부의 view()가 실행됨---->self.dispatch_request---->MethodView의 dispatch_request
    -MethodView의 dispatch_request
      def dispatch_request(self, **kwargs):
        # 현재 뷰 클래스에서 요청 방식의 소문자(get)를 반사하여 메서드를 찾음
        meth = getattr(self, request.method.lower(), None)
        # get() 메서드 실행
        return meth(**kwargs) 

6.4 LoginView.as_view(name='login')

# 세 번째 문제점: LoginView.as_view(name='login')에서 name의 용도와 필수적 이유
    -endpoint의 용도를 먼저 살펴보자. 일반 FBV에서 endpoint를 지정하지 않으면 함수명이 별칭으로 사용됨. endpoint는 어떻게 설정되는가?
    -endpoint가 None이면 함수명을 endpoint 값으로 사용
      if endpoint is None:
            endpoint = _endpoint_from_view_func(view_func)# view_func.__name__
        options["endpoint"] = endpoint
        
   -LoginView.as_view(name='login')에서 name의 용도
        -app.add_url_rule('/signin', view_func=LoginView.as_view('signin'))
        -endpoint가 전달되지 않으면, LoginView.as_view('signin')는 view 함수의 메모리 주소
        -endpoint는 함수명을 값으로 사용하려고 함. 현재 모든 함수는 view이므로 name을 전달하여 view 함수의 이름을 변경해야 함
        -endpoint가 전달되면 별칭은 endpoint를 따르고, 전달되지 않으면 name을 따름
        app.add_url_rule('/signin', view_func=LoginView.as_view(name='signin'),endpoint='auth')

6.5 View 상속으로 CBV 작성

# View를 상속받아 뷰 클래스(CBV) 작성
    -1 View를 상속받는 뷰 클래스는 실행 흐름이 동일합니다
    -2 요청이 오고 라우트가 매칭되면 self.dispatch_request가 실행됩니다
    -3 self.dispatch_request는 구현되어 있지 않으며, NotImplementedError() 예외를 발생시킵니다
    
    -4 반드시 dispatch_request를 오버라이드하여 자신의 매칭 규칙과 다른 메서드 실행 로직을 구현해야 합니다

6.6 CBV의 methods 속성

# 뷰 클래스의 methods = ['POST'] 속성
    -허용할 HTTP 메서드를 제어하는 데 사용됩니다
    -지정하지 않으면 작성된 메서드에 해당하는 요청만 허용됩니다

7 템플릿 문법

from flask import Flask, render_template,Markup
app = Flask(__name__)
@app.route('/')
def main():
    # return render_template('index.html', username='홍길동', age=25)
    # return render_template('index.html',
    #                        users={
    #                            1: {'name': '홍길동', 'age': 25, 'hobby': '축구'},
    #                            2: {'name': '이순신', 'age': 30, 'hobby': '배구'},
    #                            3: {'name': '유관순', 'age': 28, 'hobby': '농구'},
    #                        })

    link='<a href="http://www.naver.com">네이버로 이동</a>'
    # link=Markup(link)
    return render_template('index.html', link=link)
if __name__ == '__main__':
    app.run()

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>플라스크 템플릿 예제</title>
</head>
<body>
{#{{ username }}---{{ age }}#}


{#| {{ k }} | {{ v.name }} | {{ v\['name'\] }} | {{ v.get('name') }} | [상세 보기](</detail/{{ k }}>) |
|---|---|---|---|---|#}


{#안녕하세요 {{ username }}!
=====================

안녕하세요 방문자!
==========#}


{#{{ link|safe }}#}
{{ link}}


</body>
</html>

태그: 플라스크 파이썬 웹 프레임워크 웹 개발

7월 11일 16:09에 게시됨