HOWTO · Flask

Flask에서 url_for를 사용하여 동적 URL 만들기

이 설명을 통해 url_for() 함수가 하는 일과 Flask에서 동적 URL을 만드는 방법을 배웁니다. 또한 템플릿 내에서 url_for()를 사용하는 방법도 배웁니다.

이 페이지의 내용

Flask에서 url_for()는 엔드포인트의 URL을 만듭니다. 엔드포인트는 보통 뷰 함수의 이름입니다. 동적 경로를 채우려면 라우트 값을 키워드 인수로 전달합니다. 이 함수는 URL 문자열을 반환합니다. 브라우저를 해당 URL로 이동시키려면 뷰에서 redirect() 응답을 반환해야 합니다.

url_for()가 URL을 만드는 방식

Flask는 각 뷰를 엔드포인트에 연결합니다. 기본적으로 엔드포인트는 뷰 함수의 이름이므로 url_for("index")는 index라는 뷰를 가리킵니다. Flask는 해당 엔드포인트에 연결된 라우트를 찾아 URL을 만듭니다. 따라서 애플리케이션 곳곳에 경로 문자열을 중복해서 작성하는 대신 링크를 라우트 정의에 연결해 둘 수 있습니다.

결과는 / 또는 /users/Harry와 같은 경로입니다. 라우트에 변수 구간이 있다면 이름이 일치하는 키워드 인수로 값을 전달하세요. 라우트에 포함되지 않은 추가 값은 쿼리 매개변수로 추가됩니다. URL을 생성해도 요청이 전송되거나 방문자가 리디렉션되지는 않습니다.

뷰 함수에서 URL 만들기

다음의 간단한 앱은 홈 뷰, 프로필 뷰, 리디렉션을 처리하는 뷰, Jinja 페이지를 정의합니다. 테스트 클라이언트는 서버를 시작하지 않고 Jinja 페이지를 요청한 뒤 리디렉션 응답을 확인합니다. 실행하기 전에 Python 환경에 Flask를 설치하세요. 제공된 런타임에서 테스트 클라이언트는 링크를 렌더링했고, Location 헤더에 /users/Harry가 담긴 302 응답을 받았습니다.

다음 예제를 실행하세요.

from flask import Flask, redirect, render_template_string, url_for

app = Flask(__name__)


@app.get("/")
def index():
    return "Home"


@app.get("/users/<string:user_name>")
def profile(user_name):
    return f"Profile: {user_name}"


@app.get("/go")
def go():
    return redirect(url_for("profile", user_name="Harry"))


@app.get("/links")
def links():
    return render_template_string(
        '<a href="{{ url_for(\'profile\', user_name=\'Josh\') }}">Profile</a>'
    )


with app.test_client() as client:
    page = client.get("/links")
    print(page.get_data(as_text=True))
    response = client.get("/go", follow_redirects=False)
    print(response.status_code)
    print(response.headers["Location"])
<a href="/users/Josh">Profile</a>
302
/users/Harry

엔드포인트 인수는 뷰 함수 이름인 profile입니다. Flask가 /go를 처리하면 url_for()가 프로필 경로를 만들고 redirect()가 해당 경로로 이동하라는 리디렉션 응답을 반환합니다. 테스트 클라이언트는 렌더링된 링크를 출력한 다음 리디렉션 상태와 Location 헤더를 출력합니다. 렌더링된 링크의 표시 문구 Profile은 예제에서 영어로 유지됩니다. 같은 앱에서 url_for("index")를 사용하면 홈 경로를 만들 수 있습니다.

동적 라우트 값 전달하기

라우트 /users/<string:user_name>은 user_name이라는 변수를 선언합니다. url_for("profile", user_name="Harry") 호출은 같은 변수에 값을 전달합니다. Flask는 그 값을 경로에 넣고 필요하면 URL 인코딩을 적용합니다. 엔드포인트와 각 라우트 변수 이름이 뷰 및 키워드 인수와 일치하도록 하세요. 이름이 일치하지 않으면 URL을 만들 때 해당 라우트를 찾을 수 없습니다.

/articles/<int:article_id>와 같은 라우트에는 url_for("article", article_id=42)처럼 정수를 전달합니다. sort="recent"처럼 라우트 변수가 사용하지 않는 값은 쿼리 매개변수가 됩니다. 경로 구조에는 라우트 변수를 사용하고, 쿼리 데이터에는 추가 키워드 인수를 사용하세요.

생성한 URL로 리디렉션하기

뷰 안에서 redirect(url_for("profile", user_name="Harry"))를 반환하세요. url_for()는 목적지 경로를 제공하고, redirect()는 브라우저에 해당 경로로 이동하라고 알리는 HTTP 응답을 만듭니다. 예제의 /go 뷰가 이 방식을 사용합니다. url_for(...)만 반환하면 URL 문자열이 응답 본문으로 전송될 뿐, 브라우저가 이동하지는 않습니다.

라우트가 바뀌어도 리디렉션은 엔드포인트에 등록된 라우트를 대상으로 하므로 뷰에 경로를 하드 코딩할 필요가 없습니다. 리디렉션은 현재 요청에 대한 응답이고 브라우저가 목적지에 별도로 요청을 보낸다는 점을 고려해 사용할 리디렉션 동작을 정하세요.

Jinja 템플릿에서 링크 생성하기

Jinja 템플릿의 앵커 태그 href에 같은 엔드포인트와 라우트 값을 사용하세요.

<a href="{{ url_for('profile', user_name='Josh') }}">Profile</a>

여기서 profile은 뷰 이름과 일치하고 user_name은 필수 라우트 구간을 채웁니다. 실행 가능한 예제는 /links에서 이 템플릿 문자열을 렌더링하므로 생성된 링크는 프로필 라우트를 가리킵니다. 파일에 저장한 템플릿을 사용하려면 Flask의 render_template("index.html")로 반환하고 해당 파일을 애플리케이션의 templates 디렉터리에 두세요. 대상 엔드포인트가 선언하지 않은 라우트 값을 전달하지 말고 애플리케이션에 사용된 엔드포인트 철자를 정확히 사용하세요.