Blueprint trong Flask - Python

Xin chào. Mình có chút vấn đề với Blueprint trong Flask Python. Mình muốn dùng Blueprint để tách phần router ra khỏi launcher khi tạo app. Để re-structure lại folder theo kiên trúc MVC. Nhưng khi render templates ở trong router thì lỗi.

Folder structure
|-- routers
    |-- __init__.py
    |-- router.py # có thể tách thành nhiều router nhưng mình demo 1 cái
|-- views
    |-- statics
        |-- css
        |-- js
        |-- img
    |-- templates
        |-- home.html
|-- launcher.py # chỉ run app, không để router trong phần này

File launcher.py

from flask import Flask
from routers import app_router
app = Flask(__name__)
app.register_blueprint(app_router)
if __name__ == "__main__":
	app.run()

File routers/init.py

from flask import Blueprint
app_router = Blueprint('app_router', __name__)
from .router import *

File routers/router.py

from . import app_router
from flask import render_template
@app_router.route("/")
def home():
    return render_template("home.html") # error with static, template folder

Mình đã thử set templates folder, static_url_path, static_folder attribute khi tao app hoặc tạo blueprint nhưng cứ gặp 2 lỗi

werkzeug.routing.BuildError: Could not build url for endpoint ‘home’. Did you mean ‘static’ instead?
jinja2.exceptions.TemplateNotFound: home.html

class flask.Blueprint(static_folder=None, static_url_path=None, template_folder=None, url_prefix=None, root_path=None)
class flask.Flask(static_url_path=None, static_folder='static', template_folder='templates', root_path=None)

Help me, Tks

Thư mục mặc định của cả template lẫn static là templates và static bạn lại nhét vào views/templates và views/static thì tất nhiên lỗi là đúng rồi

4 Likes

Mình biết static, templates mặc định ở root path của app. Nhưng khi tạo blueprint thì mỗi module sẽ có 1 root path và resource folder riêng. Và đó chỉ là mặc định, flask cho custom, mình thấy nhiều cách custom nhưng chưa cách nào giống ý mình. Nếu để mặc định thì mình thấy structure folder không hợp lý theo thiết kế của mình lắm.

flask cho custom nhưng bạn không custom thì đương nhiên flask sẽ phải hoạt động theo mặc định rồi. Bạn không đưa các view và static vào đúng thư mục mà nó yêu cầu thì tất nhiên lỗi rồi
Giải pháp là hoặc đưa các view về lại theo mặc định hoặc bạn sẽ phải config lại. Mình không rõ khi custom bị vấn đề gì mà lại không đúng ý bạn

4 Likes

Mình lên đây để hỏi chỗ “hoặc bạn sẽ phải config lại.” Flask rất linh động nên có rất nhiều các custom static và templates folder. Cách mình muốn là làm theo MVC đó b. Model, view, control. Mình muốn để view riêng, router riêng. Bạn đọc lại post của mình sẽ thấy mình nêu rõ ý và có cả ví dụ r mà

VIEW chỉ để html, js, css, img, font…
Còn router mình để riêng ra 1 file router.py
và view để ở thư mục gốc
Đấy là ý của mình

Việc dùng thư mục static , template mặc định chỉ cho các dự án nhỏ. Nếu bạn làm dự án to chút thì sẽ hiểu tại sao phải custom lại.

Mình cần giải pháp giải quyết vấn đề đang gặp, chứ giải pháp dùng mặc định để chạy được thì k phải giải pháp mình cần tìm :smile:

Flask cho phép bạn custom lại path mà. Tại sao bạn không dùng. Config lại static_folder và template_folder ở Flask object là OK mà

4 Likes

đây nè :V https://flask.palletsprojects.com/en/1.1.x/api/?highlight=flask#flask.Flask

trong file launcher.py sửa lại là

from flask import Flask
from routers import app_router
app = Flask(__name__,  template_folder='views/template', static_folder='views/statics')
app.register_blueprint(app_router)
if __name__ == "__main__":
	app.run()

hoặc config trong Blueprint: file routers/init.py, khỏi config ở launcher cũng được:

from flask import Blueprint
app_router = Blueprint('app_router', __name__, template_folder='../views/template', static_folder='../views/statics')
from .router import *

cái ../ thử xem có được ko :V

sửa static_folder rồi coi lại static_url gì đó có còn đúng ko :V Chắc phải thêm static_url_path='static' vào nữa :V

à tên thư mục static khỏi thêm s vào thấy kì kì :V

2 Likes

ở trên mình có nói là đã config trong app khi create và trong blueprint rồi

app_router = Blueprint('app_router', __name__, template_folder='../views/template', static_folder='../views/statics')
app = Flask(__name__,  template_folder='views/template', static_folder='views/statics')

Nhưng vẫn bị lỗi này
jinja2.exceptions.TemplateNotFound: signin.html

Còn static_url_path=‘static’, thì cần ‘’ ở đầu.

app_router = Blueprint('app_router', __name__, template_folder='views/template', static_folder='views/statics', static_url_path='statics')

vẫn bị lỗi trên

Mình config rồi nhưng vẫn lỗi đó bạn
Ví dụ như folder structure trên thì mình cần phải config
static_url_path
static_folder
templates_folder
như ntn

bạn config như thế nào, gửi nốt lên xem sao

2 Likes

Trong blueprint và ngoài launcher mình đã thử các cách

app_router.static_url_path  = "/views/static"
app_router.static_folder= "/home/ubuntu/snfi_webapp/views/static"
app_router.template_folder = "views/templates"
app_router.root_path = "/home/ubuntu/snfi_webapp" # đây là thư mục gốc của project

Mặc định của flask ntn

    print(
        snfi_webapp.static_folder,
        snfi_webapp.static_url_path,
        snfi_webapp.template_folder,
        snfi_webapp.root_path,
        sep="\n"
    )

Kết quả

/home/ubuntu/snfi_webapp/static
/static
templates
/home/ubuntu/snfi_webapp

Bạn config luyên thuyên rồi.
Bạn dùng đường dẫn tuyệt đối thế thì có chắc là có tồn tại thư mục tại đường dẫn đó không.
static_folder và template_folder phải là đường dẫn tương đối (theo root path) hoặc tuyệt đối (dùng lênh cd với đường dẫn này cũng có thể vào được)
static_url_path là path sử dụng trên web url. ví dụ với config sau thì url sẽ là
static_url_path = "/this_is_static" http://domain.example/this_is_static

3 Likes

Mình deploy remove từ pycharm lên EC2 AWS. Khi deploy thì nó tự sync code theo path mình set nên chắc chắc tồn tại path.Theo bạn thì phải làm ntn

Vì mình thử lấy các path mặc định thì thấy như sau

 print(
        snfi_webapp.static_folder,
        snfi_webapp.static_url_path,
        snfi_webapp.template_folder,
        snfi_webapp.root_path,
        sep="\n"
    )

/home/ubuntu/snfi_webapp/static
/static
templates
/home/ubuntu/snfi_webapp

Nên mình set theo nó

snfi_webapp.static_url_path  = "/views/static"
snfi_webapp.static_folder= "/home/ubuntu/snfi_webapp/views/static"
snfi_webapp.template_folder = "views/templates"
snfi_webapp.root_path = "/home/ubuntu/snfi_webapp"

Bạn kiểm tra lại chưa, xem cấu trúc proj của bạn thì chỉ trừ khi bạn đẩy code lên thư mục root luôn thì may ra thư mục đó mới tồn tại (thường thì rsync đâu có quyền root đâu nên chắc sẽ không có quyền ghi được), không có gì chắc chắn nếu không kiểm chứng lại hết. Thường mình sẽ không hardcode thư mục như thế vì nhiều khả năng code được deploy ở thư mục khác thư mục gốc mà sẽ relative theo thư mục gốc của project thôi

3 Likes

Trong pycharm remote ssh cho set mà ta. Mình check ec2 ra như thế này

Mình k phải dân chuyên web nên hơi vật vã :smile:

@noname00 mình bị giới hạn reply không tạo reply được nữa, phải đợi 14 tiếng
static_url_path bắt buộc phải có / ở đầu mà

@qloved
Mình thử print ra path default của blueprint module và launcher thì ra kết quả như sau:
default các path trong launcher

  print(
                snfi_webapp.static_folder,
                snfi_webapp.static_url_path,
                snfi_webapp.template_folder,
                snfi_webapp.root_path,
                sep="\n"
  )

/home/ubuntu/snfi_webapp/static
/static
templates
/home/ubuntu/snfi_webapp

default các path trong blueprint

  print(
                app_router.static_folder,
                app_router.static_url_path,
                app_router.template_folder,
                app_router.root_path,
                sep="\n"
  )

None
None
None
/home/ubuntu/snfi_webapp/routers

Khi tạo blueprint không set path thì static_folder, static_url_path, template_folder = None

@noname00 hết lươt reply thì phải làm sao bạn nhỉ, đợi 14 tiếng à, mà sao lại có quy định này nhỉ, hạn chế người mới trao đổi

@noname00 @qloved

sau khi mình config lại như sau

snfi_webapp.static_folder = "views/static"
snfi_webapp.template_folder = "views/templates"

rồi print ra

print(
            snfi_webapp.static_url_path,
            snfi_webapp.static_folder,
            snfi_webapp.template_folder,
            snfi_webapp.root_path,
            sep="\n"
 )

thì ra kêt quả

/views/static
/home/ubuntu/snfi_webapp/views/static
views/templates
/home/ubuntu/snfi_webapp

và hình như templates đã tìm được nhưng static thì chưa

werkzeug.routing.BuildError: Could not build url for endpoint ‘signup’. Did you mean ‘static’ instead?

Chỗ này sai rồi bạn. Phải là "views/static" (không có dấu / ở đầu đường dẫn).

Bạn không nên config đường dẫn là đường dẫn tuyệt đối, đến lúc project chạy trên máy khác lại phiền.

Bonus: static_url_path và static_folder giống hệt nhau, không cần phải set lại static_url_path (trích docs):

static_url_path – can be used to specify a different path for the static files on the web. Defaults to the name of the static_folder folder.

root_path không cần set lại, vì docs có nói rõ

root_path – Flask by default will automatically calculate the path to the root of the application.

2 Likes

/views/static là đường dẫn tuyệt đối trong máy bạn nhé. Không phải tuyệt đối với project của bạn đâu, bạn thử cd /view/static sẽ bị lỗi ngay lập tức. Bạn nên để là view/static hoặc /home/ubuntu/snfi_webapp/view/static nhé

3 Likes

Lỗi này có thể do các đường link liên quan đến thư mục static trong code của bạn. Lưu ý các link đến css/js/img phải có dạng

{{ url_for('static', filename='css/...') }}
{{ url_for('static', filename='js/...') }}
{{ url_for('static', filename='img/...') }}
2 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?