웹사이트 검색

Python 3에서 Flask를 사용하여 웹 애플리케이션을 만드는 방법


저자는 Write for DOnations 프로그램을 선택했습니다.

소개

Flask는 작고 가벼운 Python 웹 프레임워크로 Python에서 웹 애플리케이션을 보다 쉽게 만들 수 있는 유용한 도구와 기능을 제공합니다. 단일 Python 파일만 사용하여 웹 응용 프로그램을 빠르게 빌드할 수 있으므로 개발자에게 유연성을 제공하고 새로운 개발자가 보다 쉽게 액세스할 수 있는 프레임워크입니다. 또한 Flask는 확장 가능하며 시작하기 전에 특정 디렉토리 구조를 강요하거나 복잡한 상용구 코드를 요구하지 않습니다.

이 자습서의 일부로 Bootstrap 도구 키트를 사용하여 응용 프로그램의 스타일을 지정하여 시각적으로 더 매력적으로 보이도록 합니다. 부트스트랩은 이러한 목표를 달성하기 위해 자체 HTML, CSSJavaScript 코드를 작성하지 않고도 모바일 브라우저에서도 잘 작동하도록 웹 애플리케이션에 반응형 웹 페이지를 통합하는 데 도움이 됩니다. 툴킷을 사용하면 Flask 작동 방식을 배우는 데 집중할 수 있습니다.

Flask는 Jinja 템플릿 엔진을 사용하여 변수, 루프, 목록 등과 같은 친숙한 Python 개념을 사용하여 HTML 페이지를 동적으로 빌드합니다. 이 템플릿을 이 프로젝트의 일부로 사용합니다.

이 자습서에서는 Python 3에서 Flask 및 SQLite를 사용하여 작은 웹 블로그를 구축합니다. 애플리케이션 사용자는 데이터베이스의 모든 게시물을 볼 수 있고 게시물 제목을 클릭하여 내용을 볼 수 있습니다. 새 게시물을 데이터베이스에 추가하고 기존 게시물을 수정하거나 삭제합니다.

전제 조건

이 가이드를 따르기 전에 다음이 필요합니다.

  • 로컬 Python 3 프로그래밍 환경인 경우 로컬 컴퓨터에 대한 Python 3 시리즈용 로컬 프로그래밍 환경을 설치 및 설정하는 방법의 배포용 자습서를 따르십시오. 이 자습서에서는 프로젝트 디렉터리를 flask_blog라고 합니다.
  • Python 3 시리즈의 코딩 방법과 같은 Python 3 개념에 대한 이해

1단계 - Flask 설치

이 단계에서는 Python 환경을 활성화하고 pip 패키지 설치 프로그램을 사용하여 Flask를 설치합니다.

프로그래밍 환경을 아직 활성화하지 않은 경우 프로젝트 디렉터리(flask_blog)에 있는지 확인하고 다음 명령을 사용하여 환경을 활성화합니다.

  1. source env/bin/activate

프로그래밍 환경이 활성화되면 프롬프트에 다음과 같은 env 접두사가 붙습니다.

이 접두사는 환경 env가 현재 활성화되어 있음을 나타내며 생성 중에 이름을 지정하는 방법에 따라 다른 이름을 가질 수 있습니다.

참고: Git 설치 사용법 및 분기 소개 문서를 사용할 수 있습니다.

Git을 사용하는 경우 프로젝트와 관련되지 않은 파일 추적을 피하기 위해 .gitignore 파일에서 새로 생성된 env 디렉토리를 무시하는 것이 좋습니다.

이제 Python 패키지를 설치하고 기본 Python 시스템 설치에서 프로젝트 코드를 분리합니다. pippython을 사용하여 이 작업을 수행합니다.

Flask를 설치하려면 다음 명령을 실행합니다.

  1. pip install flask

설치가 완료되면 다음 명령을 실행하여 설치를 확인합니다.

  1. python -c "import flask; print(flask.__version__)"

python 명령줄 인터페이스를 -c 옵션과 함께 사용하여 Python 코드를 실행합니다. 다음으로 import flask;를 사용하여 flask 패키지를 가져온 다음 flask.__version__ 변수를 통해 제공되는 Flask 버전을 인쇄합니다.

출력은 다음과 유사한 버전 번호입니다.

Output
1.1.2

프로젝트 폴더, 가상 환경을 만들고 Flask를 설치했습니다. 이제 기본 애플리케이션 설정으로 이동할 준비가 되었습니다.

2단계 - 기본 애플리케이션 생성

이제 프로그래밍 환경이 설정되었으므로 Flask를 사용하기 시작합니다. 이 단계에서는 Python 파일 내에 작은 웹 응용 프로그램을 만들고 실행하여 서버를 시작하면 브라우저에 일부 정보가 표시됩니다.

flask_blog 디렉토리에서 편집을 위해 hello.py라는 파일을 열고 nano 또는 선호하는 텍스트 편집기를 사용합니다.

  1. nano hello.py

hello.py 파일은 HTTP 요청을 처리하는 방법에 대한 최소한의 예제 역할을 합니다. 내부에서 Flask 개체를 가져오고 HTTP 응답을 반환하는 함수를 만듭니다. hello.py 안에 다음 코드를 작성합니다.

from flask import Flask

app = Flask(__name__)


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

이전 코드 블록에서는 먼저 flask 패키지에서 Flask 개체를 가져옵니다. 그런 다음 이를 사용하여 이름이 app인 Flask 애플리케이션 인스턴스를 생성합니다. 현재 Python 모듈의 이름을 보유하는 특수 변수 __name__를 전달합니다. 위치를 인스턴스에 알리는 데 사용됩니다. Flask가 배후에서 몇 가지 경로를 설정하기 때문에 이것이 필요합니다.

app 인스턴스를 생성하면 이를 사용하여 수신 웹 요청을 처리하고 사용자에게 응답을 보냅니다. @app.route는 일반 Python 함수를 Flask 뷰 함수로 바꾸는 데코레이터입니다. 이 함수는 함수의 반환 값을 HTTP 클라이언트가 표시할 HTTP 응답으로 변환합니다. , 웹 브라우저와 같은. / 값을 @app.route()에 전달하여 이 함수가 URL /에 대한 웹 요청에 응답함을 나타냅니다. 기본 URL.

hello() 보기 함수는 Hello, World! 문자열을 응답으로 반환합니다.

파일을 저장하고 닫습니다.

웹 애플리케이션을 실행하려면 먼저 FLASK_APP 환경 변수를 사용하여 애플리케이션(귀하의 경우 hello.py 파일)을 찾을 위치를 Flask에 알려야 합니다.

  1. export FLASK_APP=hello

그런 다음 FLASK_ENV 환경 변수를 사용하여 개발 모드에서 실행합니다.

  1. export FLASK_ENV=development

마지막으로 flask run 명령을 사용하여 애플리케이션을 실행합니다.

  1. flask run

응용 프로그램이 실행되면 출력은 다음과 같습니다.

Output
* Serving Flask app "hello" (lazy loading) * Environment: development * Debug mode: on * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) * Restarting with stat * Debugger is active! * Debugger PIN: 813-894-335

이전 출력에는 다음과 같은 여러 정보가 있습니다.

  • 실행 중인 애플리케이션의 이름
  • 애플리케이션이 실행되는 환경.
  • 디버그 모드: 켜기는 Flask 디버거가 실행 중임을 나타냅니다. 이것은 문제가 발생했을 때 자세한 오류 메시지를 제공하여 문제 해결을 쉽게 해주기 때문에 개발할 때 유용합니다.
  • 응용 프로그램이 URL http://127.0.0.1:5000/에서 로컬로 실행 중이며, 127.0.0.1은 컴퓨터의 localhost를 나타내는 IP입니다. :5000은 포트 번호입니다.

브라우저를 열고 URL http://127.0.0.1:5000/을 입력하면 응답으로 Hello, World! 문자열을 받게 됩니다. 응용 프로그램이 성공적으로 실행 중입니다.

경고 Flask는 간단한 웹 서버를 사용하여 개발 환경에서 응용 프로그램을 제공합니다. 즉, Flask 디버거가 실행되어 오류를 더 쉽게 잡을 수 있습니다. 이 개발 서버는 프로덕션 배포에 사용하면 안 됩니다. Flask 배포 자습서를 참조하세요.

이제 터미널에서 실행 중인 개발 서버를 그대로 두고 다른 터미널 창을 열 수 있습니다. hello.py가 있는 프로젝트 폴더로 이동하여 가상 환경을 활성화하고 FLASK_ENVFLASK_APP 환경 변수를 설정한 다음 계속 진행합니다. 다음 단계. (이러한 명령은 이 단계의 앞부분에 나열되어 있습니다.)

참고: 새 터미널을 열 때 가상 환경을 활성화하고 환경 변수 FLASK_ENVFLASK_APP를 설정하는 것을 기억하는 것이 중요합니다.

Flask 애플리케이션의 개발 서버가 이미 실행 중인 동안에는 동일한 flask run 명령으로 다른 Flask 애플리케이션을 실행할 수 없습니다. 이는 flask run이 기본적으로 포트 번호 5000을 사용하기 때문이며, 포트 번호를 가져오면 다른 응용 프로그램을 실행할 수 없게 되어 다음과 유사한 오류가 발생합니다. 수행원:

Output
OSError: [Errno 98] Address already in use

이 문제를 해결하려면 CTRL+C를 통해 현재 실행 중인 서버를 중지한 다음 flask run을 다시 실행하거나 두 가지를 동시에 실행하려면 -p 인수에 다른 포트 번호를 전달할 수 있습니다. 예를 들어 포트 5001에서 다른 애플리케이션을 실행하려면 다음 명령을 사용하십시오.

  1. flask run -p 5001

이제 작은 Flask 웹 애플리케이션이 생겼습니다. 애플리케이션을 실행하고 웹 브라우저에 정보를 표시했습니다. 다음으로 애플리케이션에서 HTML 파일을 사용합니다.

3단계 - HTML 템플릿 사용

현재 애플리케이션은 HTML 없이 간단한 메시지만 표시합니다. 웹 애플리케이션은 주로 HTML을 사용하여 방문자를 위한 정보를 표시하므로 이제 웹 브라우저에 표시할 수 있는 HTML 파일을 앱에 통합하는 작업을 할 것입니다.

Flask는 Jinja 템플릿 엔진을 사용할 수 있는 render_template() 도우미 함수를 제공합니다. 이렇게 하면 .html 파일에 HTML 코드를 작성하고 HTML 코드의 논리를 사용하여 HTML을 훨씬 쉽게 관리할 수 있습니다. 이러한 HTML 파일(템플릿)을 사용하여 현재 블로그 게시물을 표시할 기본 페이지, 블로그 게시물의 페이지, 여기서 사용자는 새 게시물을 추가할 수 있습니다.

이 단계에서는 기본 Flask 애플리케이션을 새 파일에 만듭니다.

먼저 flask_blog 디렉토리에서 nano 또는 좋아하는 편집기를 사용하여 app.py 파일을 만들고 편집합니다. 여기에는 블로깅 애플리케이션을 만드는 데 사용할 모든 코드가 포함됩니다.

  1. nano app.py

이 새 파일에서 Flask 객체를 가져와서 이전과 마찬가지로 Flask 애플리케이션 인스턴스를 만듭니다. 또한 만들려는 templates 폴더에 있는 HTML 템플릿 파일을 렌더링할 수 있는 render_template() 도우미 함수를 가져올 것입니다. 파일에는 기본 / 경로에 대한 요청을 처리하는 단일 보기 기능이 있습니다. 다음 콘텐츠를 추가합니다.

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html')

index() 보기 함수는 index.html을 인수로 사용하여 render_template()을 호출한 결과를 반환합니다. 이는 render_template( ) 템플릿 폴더에서 index.html이라는 파일을 찾습니다. 폴더와 파일이 아직 존재하지 않으므로 이 시점에서 응용 프로그램을 실행하면 오류가 발생합니다. 그럼에도 불구하고 실행하므로 일반적으로 발생하는 이 예외에 익숙합니다. 그런 다음 필요한 폴더와 파일을 만들어 수정합니다.

파일을 저장하고 종료합니다.

CTRL+C를 사용하여 hello 애플리케이션을 실행하는 다른 터미널에서 개발 서버를 중지합니다.

애플리케이션 hello를 더 이상 사용하지 않으므로 애플리케이션을 실행하기 전에 FLASK_APP 환경 변수의 값을 올바르게 지정했는지 확인하세요.

  1. export FLASK_APP=app
  2. flask run

브라우저에서 URL http://127.0.0.1:5000/을 열면 index.html 템플릿을 찾을 수 없다는 디버거 페이지가 표시됩니다. 이 오류의 원인이 된 코드의 기본 줄이 강조 표시됩니다. 이 경우 return render_template(index.html) 행입니다.

이 줄을 클릭하면 디버거가 더 많은 코드를 표시하여 문제를 해결하는 데 도움이 되는 더 많은 컨텍스트를 얻을 수 있습니다.

이 오류를 수정하려면 flask_blog 디렉터리 내에 templates라는 디렉터리를 만드세요. 그런 다음 그 안에서 편집을 위해 index.html이라는 파일을 엽니다.

  1. mkdir templates
  2. nano templates/index.html

다음으로 index.html 안에 다음 HTML 코드를 추가합니다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>FlaskBlog</title>
</head>
<body>
   <h1>Welcome to FlaskBlog</h1>
</body>
</html>

파일을 저장하고 브라우저를 사용하여 http://127.0.0.1:5000/로 다시 이동하거나 페이지를 새로 고칩니다. 이번에는 브라우저가 <h1> 태그에 Welcome to FlaskBlog 텍스트를 표시해야 합니다.

templates 폴더 외에도 Flask 웹 애플리케이션에는 일반적으로 애플리케이션에서 사용하는 CSS 파일, JavaScript 파일 및 이미지와 같은 정적 파일을 호스팅하기 위한 static 폴더가 있습니다.

style.css 스타일 시트 파일을 생성하여 애플리케이션에 CSS를 추가할 수 있습니다. 먼저 기본 flask_blog 디렉토리 안에 static이라는 디렉토리를 만듭니다.

  1. mkdir static

그런 다음 static 디렉토리 내에 .css 파일을 호스팅할 다른 css 디렉토리를 만듭니다. 이것은 일반적으로 정적 파일을 전용 폴더에 구성하기 위해 수행됩니다. 예를 들어 JavaScript 파일은 일반적으로 js라는 디렉토리 안에 있고 이미지는 images(또는 <img) 등이 있습니다. 다음 명령은 static 디렉토리 내에 css 디렉토리를 생성합니다.

  1. mkdir static/css

그런 다음 편집을 위해 css 디렉토리 내의 style.css 파일을 엽니다.

  1. nano static/css/style.css

style.css 파일에 다음 CSS 규칙을 추가합니다.

h1 {
    border: 2px #eee solid;
    color: brown;
    text-align: center;
    padding: 10px;
}

CSS 코드는 테두리를 추가하고 색상을 갈색으로 변경하고 텍스트를 중앙에 배치하고 <h1> 태그에 약간의 여백을 추가합니다.

파일을 저장하고 닫습니다.

다음으로 편집을 위해 index.html 템플릿 파일을 엽니다.

  1. nano templates/index.html

index.html 템플릿 파일의 <head> 섹션 내에 style.css 파일에 대한 링크를 추가합니다.

. . .
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="{{ url_for('static', filename= 'css/style.css') }}">
    <title>FlaskBlog</title>
</head>
. . .

여기에서 url_for() 도우미 함수를 사용하여 적절한 파일 위치를 생성합니다. 첫 번째 인수는 정적 파일에 연결하고 있음을 지정하고 두 번째 인수는 정적 디렉토리 내의 파일 경로입니다.

파일을 저장하고 닫습니다.

애플리케이션의 인덱스 페이지를 새로고침하면 Welcome to FlaskBlog 텍스트가 이제 갈색으로 중앙에 정렬되고 테두리 안에 있음을 알 수 있습니다.

CSS 언어를 사용하여 응용 프로그램의 스타일을 지정하고 고유한 디자인을 사용하여 더 매력적으로 만들 수 있습니다. 그러나 웹 디자이너가 아니거나 CSS에 익숙하지 않은 경우 애플리케이션 스타일을 지정하기 위해 사용하기 쉬운 구성 요소를 제공하는 Bootstrap 툴킷을 사용할 수 있습니다. 이 프로젝트에서는 부트스트랩을 사용합니다.

다른 HTML 템플릿을 만든다는 것은 index.html 템플릿에 이미 작성한 대부분의 HTML 코드를 반복한다는 것을 의미한다고 추측했을 수 있습니다. 모든 HTML 파일이 상속되는 기본 템플릿 파일의 도움으로 불필요한 코드 반복을 피할 수 있습니다. 자세한 내용은 Jinja의 템플릿 상속을 참조하십시오.

기본 템플릿을 만들려면 먼저 templates 디렉토리 안에 base.html이라는 파일을 만듭니다.

  1. nano templates/base.html

base.html 템플릿에 다음 코드를 입력합니다.

<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

    <title>{% block title %} {% endblock %}</title>
  </head>
  <body>
    <nav class="navbar navbar-expand-md navbar-light bg-light">
        <a class="navbar-brand" href="{{ url_for('index')}}">FlaskBlog</a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarNav">
            <ul class="navbar-nav">
            <li class="nav-item active">
                <a class="nav-link" href="#">About</a>
            </li>
            </ul>
        </div>
    </nav>
    <div class="container">
        {% block content %} {% endblock %}
    </div>

    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
  </body>
</html>

편집이 완료되면 파일을 저장하고 닫습니다.

이전 블록에 있는 대부분의 코드는 표준 HTML이며 부트스트랩에 필요한 코드입니다. <meta> 태그는 웹 브라우저에 대한 정보를 제공하고 <link> 태그는 Bootstrap CSS 파일을 연결하며 <script> 태그는 일부 추가 Bootstrap 기능을 허용하는 JavaScript 코드에 대한 링크입니다. 자세한 내용은 Bootstrap 설명서를 확인하십시오.

그러나 다음 강조 표시된 부분은 Jinja 템플릿 엔진에만 해당됩니다.

  • {% block title %} {% endblock %}: 제목의 자리 표시자 역할을 하는 블록으로 나중에 다른 템플릿에서 사용하여 매번 전체 <head> 섹션을 다시 작성하지 않고 애플리케이션의 각 페이지에 사용자 지정 제목을 지정합니다.
  • {{ url_for(index)}}: index() 뷰 함수의 URL을 반환하는 함수 호출입니다. 이는 정적 CSS 파일을 연결하는 데 사용한 이전 url_for() 호출과 다릅니다. 뷰 함수의 이름인 하나의 인수만 사용하고 대신 함수와 연결된 경로에 연결하기 때문입니다. 정적 파일의.
  • {% block content %} {% endblock %}: 하위 템플릿에 따라 콘텐츠로 대체될 또 다른 블록( 재정의할 base.html에서 상속되는 템플릿).

이제 기본 템플릿이 있으므로 상속을 사용하여 이를 활용할 수 있습니다. index.html 파일을 엽니다.

  1. nano templates/index.html

그런 다음 내용을 다음으로 바꿉니다.

{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Welcome to FlaskBlog {% endblock %}</h1>
{% endblock %}

이 새 버전의 index.html 템플릿에서는 {% extends %} 태그를 사용하여 base.html 템플릿에서 상속합니다. 그런 다음 기본 템플릿의 content 블록을 이전 코드 블록의 content 블록 내부에 있는 것으로 교체하여 확장합니다.

content 블록에는 title 블록 내부에 Welcome to FlaskBlog 텍스트가 있는 <h1> 태그가 포함되어 있습니다. turn은 base.html 템플릿의 원래 제목 블록을 Welcome to FlaskBlog 텍스트로 바꿉니다. 이렇게 하면 동일한 텍스트가 두 번 반복되는 것을 방지할 수 있습니다. 이는 페이지의 제목과 기본 템플릿에서 상속된 탐색 모음 아래에 표시되는 제목으로 모두 작동하기 때문입니다.

템플릿 상속은 또한 필요할 때마다 반복할 필요 없이 다른 템플릿(이 경우 base.html)에 있는 HTML 코드를 재사용할 수 있는 기능을 제공합니다.

파일을 저장하고 닫은 후 브라우저에서 인덱스 페이지를 새로 고칩니다. 탐색 모음과 스타일이 지정된 제목이 있는 페이지가 표시됩니다.

Flask에서 HTML 템플릿과 정적 파일을 사용했습니다. 또한 Bootstrap을 사용하여 코드 반복을 피하기 위해 페이지 및 기본 템플릿의 모양을 다듬기 시작했습니다. 다음 단계에서는 애플리케이션 데이터를 저장할 데이터베이스를 설정합니다.

4단계 - 데이터베이스 설정

이 단계에서는 데이터, 즉 애플리케이션의 블로그 게시물을 저장할 데이터베이스를 설정합니다. 또한 몇 가지 예제 항목으로 데이터베이스를 채울 것입니다.

이 자습서를 사용합니다.

첫째, SQLite의 데이터는 테이블과 열에 저장되고 데이터는 주로 블로그 게시물로 구성되기 때문에 먼저 필요한 열이 있는 posts라는 테이블을 만들어야 합니다. 몇 개의 열이 있는 posts 테이블을 만드는 SQL 명령이 포함된 .sql 파일을 만듭니다. 그런 다음 이 파일을 사용하여 데이터베이스를 만듭니다.

flask_blog 디렉터리 내에서 schema.sql이라는 파일을 엽니다.

  1. nano schema.sql

이 파일에 다음 SQL 명령을 입력하십시오.

DROP TABLE IF EXISTS posts;

CREATE TABLE posts (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    title TEXT NOT NULL,
    content TEXT NOT NULL
);

파일을 저장하고 닫습니다.

첫 번째 SQL 명령은 DROP TABLE IF EXISTS posts;입니다. 이 명령은 posts라는 기존 테이블을 삭제하므로 혼란스러운 동작이 발생하지 않습니다. 이렇게 하면 이러한 SQL 명령을 사용할 때마다 데이터베이스에 있는 모든 콘텐츠가 삭제되므로 이 자습서를 완료하고 최종 결과를 실험할 때까지 웹 애플리케이션에 중요한 콘텐츠를 작성하지 않도록 하십시오. 다음으로 CREATE TABLE posts는 다음 열이 있는 posts 테이블을 만드는 데 사용됩니다.

  • id: 기본 키를 나타내는 정수로, 각 항목(즉, 블로그 게시물)에 대해 데이터베이스에서 고유한 값을 할당합니다.
  • created: 블로그 게시물이 생성된 시간입니다. NOT NULL은 이 열이 비어 있으면 안 되며 DEFAULT 값이 게시물이 추가된 시간인 CURRENT_TIMESTAMP 값임을 나타냅니다. 데이터베이스에. id와 마찬가지로 이 열은 자동으로 채워지므로 값을 지정할 필요가 없습니다.
  • 제목: 게시물 제목입니다.
  • content: 게시물 내용입니다.

이제 schema.sql 파일에 SQL 스키마가 있으므로 이를 사용하여 SQLite .db 데이터베이스 파일을 생성하는 Python 파일을 사용하여 데이터베이스를 생성합니다. . 원하는 편집기를 사용하여 flask_blog 디렉터리 내에서 init_db.py라는 파일을 엽니다.

  1. nano init_db.py

그리고 다음 코드를 추가합니다.

import sqlite3

connection = sqlite3.connect('database.db')


with open('schema.sql') as f:
    connection.executescript(f.read())

cur = connection.cursor()

cur.execute("INSERT INTO posts (title, content) VALUES (?, ?)",
            ('First Post', 'Content for the first post')
            )

cur.execute("INSERT INTO posts (title, content) VALUES (?, ?)",
            ('Second Post', 'Content for the second post')
            )

connection.commit()
connection.close()

먼저 sqlite3 모듈을 가져온 다음 Python 파일을 실행하면 생성될 database.db라는 데이터베이스 파일에 대한 연결을 엽니다. 그런 다음 open() 함수를 사용하여 schema.sql 파일을 엽니다. 다음으로 execute() 메서드를 사용하여 콘텐츠를 실행하여 두 개의 INSERT SQL 문을 실행하여 posts 테이블에 두 개의 블로그 게시물을 추가합니다. 마지막으로 변경 사항을 커밋하고 연결을 닫습니다.

파일을 저장하고 닫은 다음 python 명령을 사용하여 터미널에서 실행합니다.

  1. python init_db.py

파일 실행이 완료되면 database.db라는 새 파일이 flask_blog 디렉토리에 나타납니다. 이는 데이터베이스를 성공적으로 설정했음을 의미합니다.

다음 단계에서는 데이터베이스에 삽입한 게시물을 검색하여 애플리케이션의 홈페이지에 표시합니다.

5단계 - 모든 게시물 표시

이제 데이터베이스를 설정했으므로 index() 보기 기능을 수정하여 데이터베이스에 있는 모든 게시물을 표시할 수 있습니다.

app.py 파일을 열어 다음과 같이 수정합니다.

  1. nano app.py

첫 번째 수정을 위해 파일 맨 위에 있는 sqlite3 모듈을 가져옵니다.

import sqlite3
from flask import Flask, render_template

. . .

다음으로 데이터베이스 연결을 생성하고 반환하는 함수를 생성합니다. 가져오기 직후에 추가합니다.

. . .
from flask import Flask, render_template

def get_db_connection():
    conn = sqlite3.connect('database.db')
    conn.row_factory = sqlite3.Row
    return conn

. . .

get_db_connection() 함수는 database.db 데이터베이스 파일에 대한 연결을 연 다음 row_factory 속성을 sqlite3.Row로 설정합니다. 열에 대한 이름 기반 액세스를 가질 수 있습니다. 이는 데이터베이스 연결이 일반 Python 사전처럼 작동하는 행을 반환함을 의미합니다. 마지막으로 이 함수는 데이터베이스에 액세스하는 데 사용할 conn 연결 개체를 반환합니다.

get_db_connection() 함수를 정의한 후 index() 함수를 다음과 같이 수정합니다.

. . .

@app.route('/')
def index():
    conn = get_db_connection()
    posts = conn.execute('SELECT * FROM posts').fetchall()
    conn.close()
    return render_template('index.html', posts=posts)

이 새 버전의 index() 함수에서는 먼저 이전에 정의한 get_db_connection() 함수를 사용하여 데이터베이스 연결을 엽니다. 그런 다음 SQL 쿼리를 실행하여 posts 테이블에서 모든 항목을 선택합니다. fetchall() 메서드를 구현하여 쿼리 결과의 모든 행을 가져오면 이전 단계에서 데이터베이스에 삽입한 게시물 목록이 반환됩니다.

close() 메서드를 사용하여 데이터베이스 연결을 닫고 index.html 템플릿 렌더링 결과를 반환합니다. 또한 데이터베이스에서 얻은 결과를 포함하는 posts 개체를 인수로 전달하면 index.html 템플릿의 블로그 게시물에 액세스할 수 있습니다.

이러한 수정이 완료되면 app.py 파일을 저장하고 닫습니다.

이제 데이터베이스에서 가져온 게시물을 index.html 템플릿으로 전달했으므로 for 루프를 사용하여 인덱스 페이지에 각 게시물을 표시할 수 있습니다.

index.html 파일을 엽니다.

  1. nano templates/index.html

그런 다음 다음과 같이 보이도록 수정합니다.

{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Welcome to FlaskBlog {% endblock %}</h1>
    {% for post in posts %}
        <a href="#">
            <h2>{{ post['title'] }}</h2>
        </a>
        <span class="badge badge-primary">{{ post['created'] }}</span>
        <hr>
    {% endfor %}
{% endblock %}

여기에서 구문 {% for post in posts %}는 Jinja for 루프이며, Python for 루프와 유사하지만 나중에 {% endfor %} 구문으로 닫아야 합니다. 이 구문을 사용하여 return render_template(index.html, posts 줄의 index() 함수에 의해 전달된 posts 목록의 각 항목을 반복합니다. =게시물). 이 for 루프 내에서 <a> 태그 내부의 <h2> 제목에 게시물 제목을 표시합니다(나중에 이 각 게시물에 개별적으로 링크하는 태그).

리터럴 변수 구분 기호({{ ... }})를 사용하여 제목을 표시합니다. post는 사전과 유사한 개체이므로 post[제목]을 사용하여 게시물 제목에 액세스할 수 있습니다. 동일한 방법을 사용하여 게시물 생성 날짜도 표시합니다.

파일 편집이 완료되면 저장하고 닫습니다. 그런 다음 브라우저에서 색인 페이지로 이동합니다. 페이지에서 데이터베이스에 추가한 두 게시물을 볼 수 있습니다.

애플리케이션 홈페이지의 데이터베이스에 있는 모든 게시물을 표시하도록 index() 보기 기능을 수정했으므로 이제 각 게시물을 단일 페이지에 표시하고 사용자가 각 개별 게시물에 연결합니다.

6단계 - 단일 게시물 표시

이 단계에서는 ID로 개별 블로그 게시물을 표시하기 위해 보기 기능과 새 HTML 템플릿을 사용하여 새 Flask 경로를 만듭니다.

이 단계가 끝나면 URL http://127.0.0.1:5000/1은 첫 번째 게시물을 표시하는 페이지가 됩니다(ID가 1이므로 ). http://127.0.0.1:5000/ID URL은 관련 ID 번호와 함께 게시물을 표시합니다. 존재하는 경우.

편집을 위해 app.py를 엽니다.

  1. nano app.py

이 프로젝트의 후반부에서 여러 위치에 있는 데이터베이스의 ID로 블로그 게시물을 가져와야 하므로 get_post()라는 독립 실행형 함수를 만듭니다. ID를 전달하여 호출하고 제공된 ID와 연결된 블로그 게시물을 다시 받거나 블로그 게시물이 존재하지 않는 경우 Flask가 404 Not Found 메시지로 응답하도록 할 수 있습니다.

404 페이지로 응답하려면 Flask와 함께 설치된 Werkzeug 라이브러리를 파일 맨 위에 가져와야 합니다.

import sqlite3
from flask import Flask, render_template
from werkzeug.exceptions import abort

. . .

그런 다음 이전 단계에서 생성한 get_db_connection() 함수 바로 뒤에 get_post() 함수를 추가합니다.

. . .

def get_db_connection():
    conn = sqlite3.connect('database.db')
    conn.row_factory = sqlite3.Row
    return conn


def get_post(post_id):
    conn = get_db_connection()
    post = conn.execute('SELECT * FROM posts WHERE id = ?',
                        (post_id,)).fetchone()
    conn.close()
    if post is None:
        abort(404)
    return post

. . .

이 새 함수에는 반환할 블로그 게시물을 결정하는 post_id 인수가 있습니다.

함수 내에서 get_db_connection() 함수를 사용하여 데이터베이스 연결을 열고 SQL 쿼리를 실행하여 주어진 post_id 값과 연결된 블로그 게시물을 가져옵니다. fetchone() 메서드를 추가하여 결과를 가져와 post 변수에 저장한 다음 연결을 닫습니다. post 변수에 None 값이 있는 경우(데이터베이스에서 결과를 찾을 수 없음을 의미) 이전에 가져온 abort() 함수를 사용하여 404 오류 코드로 응답하면 함수 실행이 완료됩니다. 그러나 게시물이 발견되면 post 변수의 값을 반환합니다.

다음으로 app.py 파일 끝에 다음 보기 기능을 추가합니다.

. . .

@app.route('/<int:post_id>')
def post(post_id):
    post = get_post(post_id)
    return render_template('post.html', post=post)

이 새로운 보기 기능에서 변수 규칙 을 추가하여 슬래시(/) 뒤의 부분이 보기 기능에서 액세스해야 하는 양의 정수( int 변환기로 표시됨). Flask는 이를 인식하고 해당 값을 post() 뷰 함수의 post_id 키워드 인수에 전달합니다. 그런 다음 get_post() 함수를 사용하여 지정된 ID와 연결된 블로그 게시물을 가져오고 결과를 post 변수에 저장하여 post에 전달합니다. 곧 만들게 될 .html 템플릿입니다.

app.py 파일을 저장하고 편집을 위해 새 post.html 템플릿 파일을 엽니다.

  1. nano templates/post.html

이 새 post.html 파일에 다음 코드를 입력합니다. 이것은 index.html 파일과 유사하지만 게시물의 내용을 표시하는 것 외에도 단일 게시물만 표시한다는 점이 다릅니다.

{% extends 'base.html' %}

{% block content %}
    <h2>{% block title %} {{ post['title'] }} {% endblock %}</h2>
    <span class="badge badge-primary">{{ post['created'] }}</span>
    <p>{{ post['content'] }}</p>
{% endblock %}

base.html 템플릿에 정의한 title 블록을 추가하여 페이지 제목이 <h2> 동시에 제목.

파일을 저장하고 닫습니다.

이제 다음 URL로 이동하여 요청한 블로그 게시물을 찾을 수 없음을 사용자에게 알려주는 페이지와 함께 데이터베이스에 있는 두 개의 게시물을 볼 수 있습니다(ID 번호가 3인 게시물이 없기 때문입니다. 지금까지):

http://127.0.0.1:5000/1
http://127.0.0.1:5000/2
http://127.0.0.1:5000/3

색인 페이지로 돌아가서 각 게시물 제목 링크를 해당 페이지로 만듭니다. url_for() 함수를 사용하여 이 작업을 수행합니다. 먼저 편집을 위해 index.html 템플릿을 엽니다.

  1. nano templates/index.html

그런 다음 href 속성 값을 #에서 {{ url_for(post, post_id=post[id]) }}로 변경하여 for 루프는 정확히 다음과 같습니다.

{% for post in posts %}
    <a href="{{ url_for('post', post_id=post['id']) }}">
        <h2>{{ post['title'] }}</h2>
    </a>
    <span class="badge badge-primary">{{ post['created'] }}</span>
    <hr>
{% endfor %}

여기에서 posturl_for() 함수에 첫 번째 인수로 전달합니다. 이것은 post() 보기 함수의 이름이며 post_id 인수를 허용하므로 post[id] 값을 지정합니다. url_for() 함수는 ID를 기반으로 각 게시물에 대한 적절한 URL을 반환합니다.

파일을 저장하고 닫습니다.

이제 인덱스 페이지의 링크가 예상대로 작동합니다. 이것으로 이제 데이터베이스에 블로그 게시물을 표시하는 애플리케이션 부분의 빌드를 완료했습니다. 다음으로 애플리케이션에 블로그 게시물을 생성, 편집 및 삭제하는 기능을 추가합니다.

7단계 - 게시물 수정

이제 웹 애플리케이션의 데이터베이스에 있는 블로그 게시물 표시를 마쳤으므로 애플리케이션 사용자가 새 블로그 게시물을 작성하고 데이터베이스에 추가하고 기존 게시물을 편집하고 불필요한 항목을 삭제할 수 있도록 허용해야 합니다. 블로그 게시물.

새 게시물 만들기

지금까지 데이터베이스에 게시물을 표시하는 애플리케이션이 있지만 SQLite 데이터베이스에 직접 연결하고 수동으로 추가하지 않는 한 새 게시물을 추가할 방법이 없습니다. 이 섹션에서는 제목과 내용을 제공하여 게시물을 작성할 수 있는 페이지를 만듭니다.

편집을 위해 app.py 파일을 엽니다.

  1. nano app.py

먼저 Flask 프레임워크에서 다음을 가져옵니다.

  • HTML 양식을 통해 제출될 들어오는 요청 데이터에 액세스하기 위한 전역 request 개체입니다.
  • URL을 생성하는 url_for() 함수
  • 요청이 처리될 때 메시지를 깜박이는 flash() 함수
  • redirect() 함수는 클라이언트를 다른 위치로 리디렉션합니다.

다음과 같이 가져오기를 파일에 추가합니다.

import sqlite3
from flask import Flask, render_template, request, url_for, flash, redirect
from werkzeug.exceptions import abort

. . .

flash() 함수는 비밀 키를 설정해야 하는 클라이언트의 브라우저 세션에 플래시된 메시지를 저장합니다. 이 비밀 키는 Flask가 새 게시물 페이지에서 인덱스 페이지로 이동하는 것과 같이 한 요청에서 다른 요청으로의 정보를 기억할 수 있도록 세션을 보호하는 데 사용됩니다. 사용자는 세션에 저장된 정보에 액세스할 수 있지만 비밀 키가 없으면 수정할 수 없으므로 누구도 비밀 키에 액세스하도록 허용해서는 안 됩니다. 자세한 내용은 세션에 대한 Flask 설명서를 참조하세요.

비밀 키를 설정하려면 app.config 개체를 통해 애플리케이션에 SECRET_KEY 구성을 추가합니다. index() 보기 함수를 정의하기 전에 app 정의 바로 뒤에 추가하십시오.

. . .
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your secret key'


@app.route('/')
def index():
    conn = get_db_connection()
    posts = conn.execute('SELECT * FROM posts').fetchall()
    conn.close()
    return render_template('index.html', posts=posts)

. . .

비밀 키는 긴 임의의 문자열이어야 한다는 점을 기억하십시오.

비밀 키를 설정한 후 새 블로그 게시물을 만들기 위해 채울 수 있는 양식을 표시하는 템플릿을 렌더링하는 보기 기능을 만듭니다. 파일 맨 아래에 이 새 함수를 추가합니다.

. . .

@app.route('/create', methods=('GET', 'POST'))
def create():
    return render_template('create.html')

이렇게 하면 GET 및 POST 요청을 모두 수락하는 /create 경로가 생성됩니다. GET 요청은 기본적으로 허용됩니다. 양식을 제출할 때 브라우저에서 보내는 POST 요청도 수락하려면 수락된 유형의 요청이 포함된 튜플을 @app.route()의 methods 인수에 전달합니다. 데코레이터.

파일을 저장하고 닫습니다.

템플릿을 만들려면 templates 폴더 내에서 create.html이라는 파일을 엽니다.

  1. nano templates/create.html

이 새 파일에 다음 코드를 추가합니다.

{% extends 'base.html' %}

{% block content %}
<h1>{% block title %} Create a New Post {% endblock %}</h1>

<form method="post">
    <div class="form-group">
        <label for="title">Title</label>
        <input type="text" name="title"
               placeholder="Post title" class="form-control"
               value="{{ request.form['title'] }}"></input>
    </div>

    <div class="form-group">
        <label for="content">Content</label>
        <textarea name="content" placeholder="Post content"
                  class="form-control">{{ request.form['content'] }}</textarea>
    </div>
    <div class="form-group">
        <button type="submit" class="btn btn-primary">Submit</button>
    </div>
</form>
{% endblock %}

이 코드의 대부분은 표준 HTML입니다. 게시물 제목에 대한 입력 상자, 게시물 내용에 대한 텍스트 영역 및 양식 제출 버튼이 표시됩니다.

게시물 제목 입력 값은 {{ request.form[title] }}이고 텍스트 영역은 {{ request.form[content] }} 값을 가지며, 이는 입력한 데이터가 잘못되어도 손실되지 않도록 하기 위한 것입니다. 예를 들어 긴 게시물을 작성하고 제목을 지정하는 것을 잊은 경우 제목이 필요하다는 메시지가 표시됩니다. 이 작업은 템플릿에서 액세스할 수 있는 request 전역 개체에 저장되기 때문에 작성한 게시물을 잃지 않고 발생합니다.

이제 개발 서버가 실행 중이면 브라우저를 사용하여 /create 경로로 이동합니다.

http://127.0.0.1:5000/create

제목 및 콘텐츠 상자가 있는 새 게시물 만들기 페이지가 표시됩니다.

이 양식은 create() 보기 기능에 POST 요청을 제출합니다. 그러나 아직 함수에서 POST 요청을 처리하는 코드가 없으므로 양식을 채우고 제출한 후에는 아무 일도 일어나지 않습니다.

양식이 제출되면 들어오는 POST 요청을 처리합니다. create() 보기 함수 내에서 이 작업을 수행합니다. request.method 값을 확인하여 POST 요청을 별도로 처리할 수 있습니다. 값이 POST로 설정되면 요청이 POST 요청임을 의미하며 제출된 데이터를 추출하고 유효성을 검사한 다음 데이터베이스에 삽입합니다.

편집을 위해 app.py 파일을 엽니다.

  1. nano app.py

정확히 다음과 같이 보이도록 create() 뷰 함수를 수정합니다.

. . .

@app.route('/create', methods=('GET', 'POST'))
def create():
    if request.method == 'POST':
        title = request.form['title']
        content = request.form['content']

        if not title:
            flash('Title is required!')
        else:
            conn = get_db_connection()
            conn.execute('INSERT INTO posts (title, content) VALUES (?, ?)',
                         (title, content))
            conn.commit()
            conn.close()
            return redirect(url_for('index'))

    return render_template('create.html')

if 문에서 request.method == POST 비교를 통해 요청이 POST 요청인 경우에만 뒤따르는 코드가 실행되도록 합니다.

그런 다음 요청의 양식 데이터에 대한 액세스를 제공하는 request.form 개체에서 제출된 제목과 콘텐츠를 추출합니다. 제목이 제공되지 않으면 제목이 아닌 경우 조건이 충족되어 사용자에게 제목이 필요함을 알리는 메시지가 표시됩니다. 반면에 제목이 제공되면 get_db_connection() 함수로 연결을 열고 받은 제목과 내용을 posts 테이블에 삽입합니다.

그런 다음 변경 사항을 데이터베이스에 커밋하고 연결을 닫습니다. 블로그 게시물을 데이터베이스에 추가한 후 url_for() 함수에 의해 생성된 URL을 전달하는 redirect() 함수를 사용하여 클라이언트를 색인 페이지로 리디렉션합니다. 값 인덱스를 인수로 사용합니다.

파일을 저장하고 닫습니다.

이제 웹 브라우저를 사용하여 /create 경로로 이동합니다.

http://127.0.0.1:5000/create

선택한 제목과 일부 내용으로 양식을 작성하십시오. 양식을 제출하면 색인 페이지에 새 게시물이 나열되는 것을 볼 수 있습니다.

마지막으로 플래시 메시지를 표시하고 이 새 페이지에 쉽게 액세스할 수 있도록 base.html 템플릿의 탐색 모음에 대한 링크를 추가합니다. 템플릿 파일을 엽니다.

  1. nano templates/base.html

<nav> 태그 내의 About 링크 다음에 새 <li> 태그를 추가하여 파일을 편집합니다. 그런 다음 content 블록 바로 위에 새 for 루프를 추가하여 내비게이션 바 아래에 깜박이는 메시지를 표시합니다. 이러한 메시지는 Flask가 제공하는 특수 get_flashed_messages() 함수에서 사용할 수 있습니다.

<nav class="navbar navbar-expand-md navbar-light bg-light">
    <a class="navbar-brand" href="{{ url_for('index')}}">FlaskBlog</a>
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarNav">
        <ul class="navbar-nav">
        <li class="nav-item">
            <a class="nav-link" href="#">About</a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="{{url_for('create')}}">New Post</a>
        </li>
        </ul>
    </div>
</nav>
<div class="container">
    {% for message in get_flashed_messages() %}
        <div class="alert alert-danger">{{ message }}</div>
    {% endfor %}
    {% block content %} {% endblock %}
</div>

파일을 저장하고 닫습니다. 탐색 모음에는 이제 /create 경로에 연결되는 New Post 항목이 있습니다.

게시물 편집

블로그를 최신 상태로 유지하려면 기존 게시물을 편집할 수 있어야 합니다. 이 섹션에서는 게시물 편집 프로세스를 단순화하기 위해 응용 프로그램에서 새 페이지를 만드는 과정을 안내합니다.

먼저 app.py 파일에 새 경로를 추가합니다. 보기 기능은 수정해야 하는 게시물의 ID를 수신하며, URL은 post_id가 포함된 /post_id/edit 형식입니다. 변수는 게시물의 ID입니다. 편집을 위해 app.py 파일을 엽니다.

  1. nano app.py

다음으로 파일 끝에 다음 edit() 뷰 함수를 추가합니다. 기존 게시물을 편집하는 것은 새 게시물을 만드는 것과 유사하므로 이 보기 기능은 create() 보기 기능과 유사합니다.

. . .

@app.route('/<int:id>/edit', methods=('GET', 'POST'))
def edit(id):
    post = get_post(id)

    if request.method == 'POST':
        title = request.form['title']
        content = request.form['content']

        if not title:
            flash('Title is required!')
        else:
            conn = get_db_connection()
            conn.execute('UPDATE posts SET title = ?, content = ?'
                         ' WHERE id = ?',
                         (title, content, id))
            conn.commit()
            conn.close()
            return redirect(url_for('index'))

    return render_template('edit.html', post=post)

편집하는 게시물은 URL에 의해 결정되며 Flask는 ID 번호를 id 인수를 통해 edit() 함수에 전달합니다. 데이터베이스에서 제공된 ID와 연결된 게시물을 가져오려면 이 값을 get_post() 함수에 추가합니다. 새 데이터는 if request.method == POST 조건 내에서 처리되는 POST 요청으로 제공됩니다.

새 게시물을 만들 때와 마찬가지로 먼저 request.form 개체에서 데이터를 추출한 다음 제목에 빈 값이 있으면 메시지를 표시하고 그렇지 않으면 데이터베이스 연결을 엽니다. 그런 다음 데이터베이스의 게시물 ID가 URL에 있던 ID와 동일한 새 제목과 새 콘텐츠를 설정하여 posts 테이블을 업데이트합니다.

GET 요청의 경우 get_post()post 변수를 전달하는 edit.html 템플릿을 렌더링합니다. > 기능. 이를 사용하여 편집 페이지에 기존 제목과 내용을 표시합니다.

파일을 저장하고 닫은 다음 새 edit.html 템플릿을 만듭니다.

  1. nano templates/edit.html

이 새 파일 안에 다음 코드를 작성합니다.

{% extends 'base.html' %}

{% block content %}
<h1>{% block title %} Edit "{{ post['title'] }}" {% endblock %}</h1>

<form method="post">
    <div class="form-group">
        <label for="title">Title</label>
        <input type="text" name="title" placeholder="Post title"
               class="form-control"
               value="{{ request.form['title'] or post['title'] }}">
        </input>
    </div>

    <div class="form-group">
        <label for="content">Content</label>
        <textarea name="content" placeholder="Post content"
                  class="form-control">{{ request.form['content'] or post['content'] }}</textarea>
    </div>
    <div class="form-group">
        <button type="submit" class="btn btn-primary">Submit</button>
    </div>
</form>
<hr>
{% endblock %}

파일을 저장하고 닫습니다.

이 코드는 {{ request.form[title] 또는 post[title] }}{{ request.form[content] 또는 post[content] }}를 제외하고 동일한 패턴을 따릅니다. 구문. 요청에 저장된 데이터가 있는 경우 이를 표시하고, 그렇지 않으면 현재 데이터베이스 데이터를 포함하는 템플릿에 전달된 post 변수의 데이터를 표시합니다.

이제 다음 URL로 이동하여 첫 번째 게시물을 편집합니다.

http://127.0.0.1:5000/1/edit

"첫 번째 게시물\ 편집 페이지가 표시됩니다.

게시물을 수정하고 양식을 제출한 다음 게시물이 업데이트되었는지 확인하십시오.

이제 인덱스 페이지의 각 게시물에 대한 편집 페이지를 가리키는 링크를 추가해야 합니다. index.html 템플릿 파일을 엽니다.

  1. nano templates/index.html

다음과 정확히 일치하도록 파일을 편집합니다.

{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Welcome to FlaskBlog {% endblock %}</h1>
    {% for post in posts %}
        <a href="{{ url_for('post', post_id=post['id']) }}">
            <h2>{{ post['title'] }}</h2>
        </a>
        <span class="badge badge-primary">{{ post['created'] }}</span>
        <a href="{{ url_for('edit', id=post['id']) }}">
            <span class="badge badge-warning">Edit</span>
        </a>
        <hr>
    {% endfor %}
{% endblock %}

파일을 저장하고 닫습니다.

여기에서 <a> 태그를 추가하여 edit() 뷰 함수에 연결하고 post[id] 값을 전달하여 연결합니다. 편집 링크가 있는 각 게시물의 편집 페이지.

게시물 삭제

때로는 게시물을 더 이상 공개할 필요가 없기 때문에 게시물 삭제 기능이 중요합니다. 이 단계에서는 애플리케이션에 삭제 기능을 추가합니다.

먼저 edit() 보기 기능과 유사하게 POST 요청을 수락하는 새로운 /ID/delete 경로를 추가합니다. 새로운 delete() 보기 기능은 URL에서 삭제할 게시물의 ID를 수신합니다. app.py 파일을 엽니다.

  1. nano app.py

파일 하단에 다음 보기 기능을 추가합니다.

# ....

@app.route('/<int:id>/delete', methods=('POST',))
def delete(id):
    post = get_post(id)
    conn = get_db_connection()
    conn.execute('DELETE FROM posts WHERE id = ?', (id,))
    conn.commit()
    conn.close()
    flash('"{}" was successfully deleted!'.format(post['title']))
    return redirect(url_for('index'))

이 보기 기능은 POST 요청만 수락합니다. 즉, 웹 브라우저는 기본적으로 GET 요청을 사용하므로 브라우저에서 /ID/delete 경로로 이동하면 오류가 반환됩니다.

그러나 삭제하려는 게시물의 ID를 전달하는 POST 요청을 보내는 양식을 통해 이 경로에 액세스할 수 있습니다. 함수는 ID 값을 수신하고 이를 사용하여 get_post() 함수로 데이터베이스에서 게시물을 가져옵니다.

그런 다음 데이터베이스 연결을 열고 DELETE FROM SQL 명령을 실행하여 게시물을 삭제합니다. 변경 사항을 데이터베이스에 커밋하고 메시지를 깜박이는 동안 연결을 닫아 게시물이 성공적으로 삭제되었음을 사용자에게 알리고 인덱스 페이지로 리디렉션합니다.

편집 페이지에 Delete 버튼만 추가하기 때문에 템플릿 파일을 렌더링하지 않습니다.

edit.html 템플릿 파일을 엽니다.

  1. nano templates/edit.html

그런 다음 <hr> 태그 뒤와 {% endblock %} 줄 바로 앞에 다음 <form> 태그를 추가합니다.

<hr>

<form action="{{ url_for('delete', id=post['id']) }}" method="POST">
    <input type="submit" value="Delete Post"
            class="btn btn-danger btn-sm"
            onclick="return confirm('Are you sure you want to delete this post?')">
</form>

{% endblock %}

confirm() 메서드를 사용하여 요청을 제출하기 전에 확인 메시지를 표시합니다.

이제 블로그 게시물의 편집 페이지로 다시 이동하여 삭제해 보십시오.

http://127.0.0.1:5000/1/edit

이 단계가 끝나면 프로젝트의 소스 코드가 이 페이지의 코드처럼 보입니다.

이를 통해 애플리케이션 사용자는 이제 새 블로그 게시물을 작성하고 데이터베이스에 추가하고 기존 게시물을 편집 및 삭제할 수 있습니다.

결론

이 자습서에서는 Flask Python 프레임워크의 필수 개념을 소개했습니다. 작은 웹 응용 프로그램을 만들고 개발 서버에서 실행하고 사용자가 URL 매개 변수 및 웹 양식을 통해 사용자 지정 데이터를 제공할 수 있도록 하는 방법을 배웠습니다. Flask 및 SQLite에서 일대다 데이터베이스 관계를 사용하는 방법도 사용했습니다.

등록된 사용자만 블로그 게시물을 만들고 수정할 수 있도록 사용자 인증을 추가하여 이 응용 프로그램을 추가로 개발할 수 있습니다. 또한 각 블로그 게시물에 대한 댓글과 태그를 추가하고 사용자가 게시물에 이미지를 포함할 수 있는 기능을 제공하는 파일 업로드를 추가할 수 있습니다. 자세한 내용은 플라스크 문서를 참조하십시오.

Flask에는 많은 커뮤니티 제작 Flask 확장 기능이 있습니다. 다음은 개발 프로세스를 더 쉽게 만들기 위해 사용할 수 있는 확장 목록입니다.

  • Flask-Login: 사용자 세션을 관리하고 로그인 및 로그아웃을 처리하고 로그인한 사용자를 기억합니다.
  • SQLAlchemy, Python SQL 툴킷 및 SQL 데이터베이스와 상호 작용하기 위한 객체 관계형 매퍼
  • Flask-Mail: Flask 애플리케이션에서 이메일 메시지를 보내는 작업을 도와줍니다.