Share via


2단계: 보기 및 페이지 템플릿을 사용하여 Flask 앱 만들기

이전 단계: Visual Studio 프로젝트 및 솔루션 만들기

이 자습서의 1단계에서는 한 페이지와 모든 코드가 단일 파일에 포함된 Flask 앱을 만들었습니다. 향후 개발을 위해서는 코드를 리팩터링하고 페이지 템플릿 구조를 만드는 것이 가장 좋습니다. 특히, 앱 보기의 코드와 시작 코드와 같은 다른 요소를 분리하는 것이 좋습니다.

이 단계에서는 다음 작업을 수행하는 방법을 배웁니다.

  • 시작 코드와 보기를 분리하기 위해 앱의 코드 리팩터링(2-1단계)
  • 페이지 템플릿을 사용하여 보기 렌더링(2-2단계)

2-1단계: 추가 개발을 지원하기 위해 프로젝트 리팩터링

"빈 Flask 웹 프로젝트" 템플릿으로 생성된 코드에는 단일 보기와 시작 코드가 포함된 단일 app.py 파일이 있습니다. 나중에 여러 보기 및 템플릿이 있는 앱을 개발하려면 이러한 문제를 구분하는 것이 가장 좋습니다.

  1. 프로젝트 폴더에서 HelloFlask라는 앱 폴더를 만듭니다(솔루션 탐색기에서 프로젝트를 마우스 오른쪽 단추로 클릭하고 추가>새 폴더를 선택함).

  2. HelloFlask 폴더에서 다음 콘텐츠가 포함된 __init__.py라는 파일을 만듭니다. 이 파일은 Flask 인스턴스를 만들고 앱의 보기를 로드합니다(다음 단계에서 생성).

    from flask import Flask
    app = Flask(__name__)
    
    import HelloFlask.views
    
  3. HelloFlask 폴더에서 다음 콘텐츠가 포함된 views.py라는 파일을 만듭니다. __init__.py 내에서 import HelloFlask.views를 사용했기 때문에 views.py라는 이름은 중요합니다. 이름이 일치하지 않으면 런타임에 오류가 표시됩니다.

    from flask import Flask
    from HelloFlask import app
    
    @app.route('/')
    @app.route('/home')
    def home():
        return "Hello Flask!"
    

    이 코드는 함수의 이름과 경로를 home으로 변경하는 것 외에도 app.py의 페이지 렌더링 코드를 포함하고 __init__.py에 선언된 app 개체를 가져옵니다.

  4. HelloFlasktemplates라는 하위 폴더를 만듭니다. 이 폴더는 현재 비어 있습니다.

  5. 프로젝트의 루트 폴더에서 app.py의 이름을 runserver.py로 바꾸고, 콘텐츠를 다음 코드와 일치시킵니다.

    import os
    from HelloFlask import app    # Imports the code from HelloFlask/__init__.py
    
    if __name__ == '__main__':
        HOST = os.environ.get('SERVER_HOST', 'localhost')
    
        try:
            PORT = int(os.environ.get('SERVER_PORT', '5555'))
        except ValueError:
            PORT = 5555
    
        app.run(HOST, PORT)
    
  6. 전체 프로젝트 구조는 다음 이미지와 같아야 합니다.

    Project structure after refactoring the code

  7. 디버그>디버깅 시작(F5)을 선택하거나 도구 모음의 웹 서버 단추를 사용(표시되는 브라우저가 다를 수 있음)하여 앱을 시작하고 브라우저를 엽니다. / 및 /home URL 경로를 둘 다 시도해 봅니다.

  8. 또한 코드의 여러 부분에서 중단점을 설정하고 앱을 다시 시작하여 시작 시퀀스를 따를 수 있습니다. 예를 들어 runserver.py 첫 번째 줄과 *HelloFlask_*init_.py 및 views.py 줄에 return "Hello Flask!"중단점을 설정합니다. 그런 다음 앱을 다시 시작(디버그>다시 시작, Ctrl+Shift+F5 또는 아래 표시된 도구 모음 단추)하고 코드를 단계별로 실행(F10)하거나 F5를 사용하여 각 중단점에서 실행합니다.

    Restart button on the debugging toolbar in Visual Studio

  9. 완료되면 앱을 중지합니다.

소스 제어에 커밋

코드를 변경하고 성공적으로 테스트한 후에는 변경 내용을 검토하고 소스 제어에 커밋할 수 있습니다. 이후 단계에서 이 자습서가 소스 제어에 다시 커밋하라는 알림을 표시하면 이 섹션을 참조할 수 있습니다.

  1. Visual Studio의 아래쪽(아래 원)에 있는 변경 단추를 선택하여 팀 탐색기로 이동합니다.

    Source control changes button on the Visual Studio status bar

  2. 팀 탐색기에서 “Refactor code”와 같은 커밋 메시지를 입력하고 모두 커밋을 선택합니다. 커밋이 완료되면 커밋 <해시>가 로컬로 생성된 메시지가 표시됩니다. 동기화하여 변경 내용을 서버와 공유합니다. 원격 리포지토리에 변경 내용을 푸시하려면 동기화를 선택한 다음 나가는 커밋에서 푸시를 선택합니다. 원격에 푸시하기 전에 여러 개의 로컬 커밋을 누적할 수도 있습니다.

    Push commits to remote in Team Explorer

질문: 소스 제어에 얼마나 자주 커밋해야 하나요?

대답: 소스 제어에 변경 내용을 커밋하면 변경 로그에 레코드가 생성되고 필요한 경우 리포지토리를 되돌릴 수 있는 지점이 생성됩니다. 각 커밋에서 특정 변경 내용을 검사할 수도 있습니다. Git 커밋은 비용이 많이 들지 않기 때문에, 한 번의 커밋에 많은 수의 변경 내용을 누적하는 것보다 커밋을 자주 수행하는 것이 좋습니다. 사소한 변경 내용을 매번 개별 파일에 커밋할 필요가 없습니다. 일반적으로 기능을 추가하거나, 이 단계에서 수행한 것과 같은 구조 변경을 수행하거나, 일부 코드를 리팩터링했을 때 커밋을 실행합니다. 또한 모두에게 가장 적합한 커밋 빈도를 다른 팀원과 함께 확인합니다.

커밋 빈도와 원격 리포지토리에 커밋을 푸시하는 빈도는 다른 문제입니다. 원격 리포지토리에 커밋을 푸시하기 전에 로컬 리포지토리에 여러 커밋을 누적할 수 있습니다. 커밋 빈도는 팀이 리포지토리를 관리하는 방법에 따라 달라집니다.

2-2단계: 템플릿을 사용하여 페이지 렌더링

지금까지 views.pyhome 함수는 페이지에 대해 일반 텍스트 HTTP 응답만 생성했습니다. 그러나 대부분의 실제 웹 페이지는 라이브 데이터를 통합하는 서식 있는 HTML 페이지로 응답합니다. 함수를 사용하여 보기를 정의하는 주된 이유는 콘텐츠를 동적으로 생성하기 위함입니다.

보기의 반환 값은 단순한 문자열이므로, 동적 콘텐츠를 사용하여 문자열 내에서 원하는 HTML을 빌드할 수 있습니다. 그러나 데이터와 태그를 분리하는 것이 가장 좋으므로, 태그를 템플릿에 배치하고 데이터를 코드에 유지하는 것이 더 좋습니다.

  1. 먼저 views.py를 편집하여 일부 동적 콘텐츠가 있는 페이지에 인라인 HTML을 사용하는 다음 코드를 포함합니다.

    from datetime import datetime
    from flask import render_template
    from HelloFlask import app
    
    @app.route('/')
    @app.route('/home')
    def home():
        now = datetime.now()
        formatted_now = now.strftime("%A, %d %B, %Y at %X")
    
        html_content = "<html><head><title>Hello Flask</title></head><body>"
        html_content += "<strong>Hello Flask!</strong> on " + formatted_now
        html_content += "</body></html>"
    
        return html_content
    
  2. 앱을 실행하고 페이지를 여러 번 새로 고쳐서 날짜/시간이 업데이트되었는지 확인합니다. 완료되면 앱을 중지합니다.

  3. 템플릿을 사용하도록 페이지 렌더링을 변환하려면 templates 폴더에 다음 콘텐츠가 포함된 index.html이라는 파일을 만듭니다. 여기서 {{ content }}는 코드에 값을 제공하는 자리 표시자 또는 대체 토큰(템플릿 변수라고도 함)입니다.

    <html>
      <head>
        <title>Hello Flask</title>
      </head>
    
      <body>
        {{ content }}
      </body>
    </html>
    
  4. render_template을 사용하여 템플릿을 로드하도록 home 함수를 수정하고, "content"에 값을 지정합니다. 이 작업은 자리 표시자의 이름과 일치하는 명명된 인수를 사용하여 수행됩니다. Flask는 templates 폴더에서 템플릿을 자동으로 찾으므로, 템플릿에 대한 선언은 해당 폴더에 상대적입니다.

    def home():
        now = datetime.now()
        formatted_now = now.strftime("%A, %d %B, %Y at %X")
    
        return render_template(
            "index.html",
            content = "<strong>Hello, Flask!</strong> on " + formatted_now)
    
  5. 앱을 실행하여 결과를 확인합니다. 템플레이팅 엔진(Jinja)이 HTML 콘텐츠를 자동으로 이스케이프하므로 content 값의 인라인 HTML이 HTML으로 렌더링되지 않습니다. 자동 이스케이프는 삽입 공격에 대한 우발적인 취약성을 방지합니다. 개발자는 종종 한 페이지에서 입력을 수집하고 템플릿 자리 표시자를 통해 그 입력을 다른 페이지의 값으로 사용합니다. 이스케이프는 HTML을 코드에 포함하지 않는 것이 최선이라는 것을 상기시켜 주는 역할도 합니다.

    따라서 templates\index.html을 검토하여 태그 내의 각 데이터 조각마다 고유한 자리 표시자를 포함하도록 합니다.

    <html>
      <head>
        <title>{{ title }}</title>
      </head>
      <body>
        <strong>{{ message }}</strong>{{ content }}
      </body>
    </html>
    

    그런 다음, home 함수를 업데이트하여 모든 자리 표시자에 값을 지정합니다.

    def home():
        now = datetime.now()
        formatted_now = now.strftime("%A, %d %B, %Y at %X")
    
        return render_template(
            "index.html",
            title = "Hello Flask",
            message = "Hello, Flask!",
            content = " on " + formatted_now)
    
  6. 앱을 다시 실행하여 올바르게 렌더링된 출력을 확인합니다.

    Running app using the template

  7. 소스 제어에 변경 내용을 커밋하고 원격 리포지토리를 업데이트할 수 있습니다. 자세한 내용은 2-1단계를 참조하세요.

질문: 페이지 템플릿은 별도의 파일에 있어야 하나요?

대답: 템플릿은 일반적으로 별도의 HTML 파일에서 유지 관리되지만 인라인 템플릿을 사용할 수도 있습니다. 태그와 코드를 명확하게 분리하려면 별도의 파일을 사용하는 것이 좋습니다.

질문: 템플릿은 .html 파일 확장명을 사용해야 하나요?

답변: 항상 render_template 함수에 대한 첫 번째 인수에서 파일의 정확한 상대 경로를 식별할 수 있으므로 페이지 템플릿 파일의 .html 확장명은 전적으로 선택 사항입니다. 그러나 Visual Studio(및 기타 편집기)는 일반적으로 .html 파일을 사용하여 코드 완성 및 구문 색 지정과 같은 기능을 제공하므로 페이지 템플릿이 HTML이 아니라는 사실보다 중요합니다.

Flask 프로젝트로 작업할 때 Visual Studio는 편집 중인 HTML 파일이 실제로 Flask 템플릿인 경우를 자동으로 감지하고 특정 자동 완성 기능을 제공합니다. 예를 들어 Flask 페이지 템플릿 주석 {#을 입력하기 시작하면 Visual Studio에서 닫는 #} 문자를 자동으로 제공합니다. 선택 영역을 주석으로 처리선택 영역의 주석 처리 제거 명령(편집>고급 메뉴 및 도구 모음)에서도 HTML 주석 대신 템플릿 주석을 사용합니다.

질문: 템플릿을 추가 하위 폴더로 구성할 수 있나요?

대답: 예, 하위 폴더를 사용한 다음, render_template에 대한 호출에서 템플릿 아래의 상대 경로를 참조할 수 있습니다. 이는 템플릿의 네임스페이스를 효과적으로 만들 수 있는 좋은 방법입니다.

다음 단계

자세히 알아보기