Chuyển đổi html sang jinja2
người hướng dẫn. [00. 01] Nếu bạn bắt đầu viết html mà máy chủ web của bạn trả về dưới dạng một chuỗi trong Python, thì bạn sẽ bắt đầu ghét cuộc sống và lựa chọn cuộc sống của bạn khá nhanh chóng Show
[00. 08] Một trong những điều chúng ta có thể làm trong Flask là tạo thư mục này có tên là Mẫu. Trong thư mục Mẫu đó, chúng ta có thể tạo một tệp html như Xin chào. html [00. 20] Điều này cho phép chúng tôi sử dụng trình chỉnh sửa của mình hoặc bất kỳ html nào được cung cấp cho chúng tôi và chỉnh sửa tệp html đó với đầy đủ lợi thế của tô sáng cú pháp và tự động hoàn thành, tất cả những nội dung tuyệt vời mà bạn nhận được [00. 31] Html này sẽ được hiển thị dưới dạng mẫu Jinja2, có nghĩa là chúng ta có thể tận dụng tối đa tất cả các tính năng của Jinja2. Ví dụ: các câu lệnh điều kiện để kiểm tra xem một biến được gọi tên có tồn tại không [00. 45] Nếu tên tham số tồn tại, chúng tôi có thể hiển thị giá trị của tham số đó trong html của mẫu của chúng tôi. Nếu tham số tên không có ở đó, chúng tôi có thể thực hiện một hành động hoàn toàn khác và sau đó chúng tôi có thể đóng logic điều kiện của mình trong mẫu [01. 03] Quay lại logic ứng dụng của chúng tôi. Tôi sẽ tạo một trình trang trí tuyến đường mới đáp ứng /hello. không có tham số ở cuối của nó [01. 15] Để phù hợp với tên tham số mà chúng tôi sử dụng trong mẫu Jinja của mình, tôi sẽ đổi tên người dùng thành tên tham số tại đây. Bây giờ, thay vì trả về chuỗi, tôi sẽ trả về mẫu kết xuất và cung cấp cho nó tên của tệp mẫu để trả về cũng như bất kỳ tham số nào mà mẫu sẽ có quyền truy cập vào [01. 36] Để điều đó hoạt động, từ Flask, chúng ta cần nhập chức năng mẫu kết xuất. Nếu tôi lưu nó và sau đó đi đến xin chào. không có tham số bổ sung nào được đính kèm, điều đó sẽ nổ tung vì chúng ta đã gọi hàm hello nhưng không bao gồm tham số bắt buộc của tên [01. 56] Chúng ta có thể giải quyết vấn đề đó bằng cách đặt tên giá trị mặc định là none. Bây giờ, khi chúng tôi gọi lại, chúng tôi nhận được "Xin chào, người không tên", được hiển thị bởi mẫu Jinja trong Xin chào của chúng tôi. tệp html [02. 11] Nếu tôi gọi nó bằng cách thêm /will vào cuối, nó sẽ nhận ra rằng đó là một tham số tên và phản hồi bằng "Xin chào, Will. " Flask là một khung web Python đang ngày càng phổ biến trong thế giới webdev. Sau khi đọc rất nhiều điều tuyệt vời về Flask, tôi quyết định tự mình dùng thử. Cá nhân tôi thấy việc thử nghiệm một khung mới rất khó khăn, bởi vì bạn phải tìm một dự án đủ phức tạp để tiết lộ những điều kỳ quặc của khung, nhưng không quá khó để lấy đi niềm vui của dự án. May mắn thay, trang web hỗ trợ PHP/Wordpress của tôi đã hoàn thành vai trò này khá tốt - trang web chỉ bao gồm nội dung tĩnh, trang liên hệ và blog. Nếu tôi không thể chuyển đổi một trang web đơn giản như vậy sang Flask, tôi sẽ biết ngay rằng tôi và Flask sẽ không thể tạo thành một nhóm ăn ý cảnh báo spoiler. Bạn đang đọc nội dung này trên một trang web do Flask cung cấp. Vui lòng kiểm tra nguồn của trang web này trên Github Bắt đầuNhiệm vụ đầu tiên trong tầm tay chỉ đơn giản là làm cho các trang chủ, về, dịch vụ và công việc hiển thị chính xác. Mặc dù nhiệm vụ chủ yếu bao gồm sao chép và dán, nhưng tôi đã có thể áp dụng ngay hầu hết các khái niệm từ hướng dẫn khởi động nhanh Flask. Cụ thể, tôi phải học
Chắc chắn rồi, việc hiển thị các tài liệu HTML thuần túy khá đơn giản. Theo HTML thuần túy, ý tôi là không có bao gồm cho đầu trang, chân trang, v.v. Do đó, bước hợp lý tiếp theo là lấy các tài liệu HTML thuần túy này và KHÔ các vùng lặp lại Đau ngày càng tăng. đã sẵn sàng?Đến từ PHP, tôi đã quen với việc chỉ {% extends "layout.html" %} {% block body %} Body content goes here! {% endblock body %}2-nhập nội dung tôi muốn và hoàn thành nó. Jinja2, công cụ tạo khuôn mẫu mặc định của Flask, hiện không hỗ trợ bao gồm. (Ghi chú. Hàm {% extends "layout.html" %} {% block body %} Body content goes here! {% endblock body %}2. Tuy nhiên, tôi không thể lấy hàm bao gồm để trả về html không thoát. Có lẽ chức năng này đã bị hỏng trong một bản dựng gần đây). Tuy nhiên, Jinja có. Để chứng minh, giả sử chúng ta có một mẫu gốc {% extends "layout.html" %} {% block body %} Body content goes here! {% endblock body %}4 {% nguyên %}
{% rút lại %} Và một mẫu con {% extends "layout.html" %} {% block body %} Body content goes here! {% endblock body %}5 kế thừa mẫu gốc và điền vào các khối của nó {% raw %} {% extends "layout.html" %} {% block body %} Body content goes here! {% endblock body %} {% rút lại %} Nếu chúng tôi gọi vào ngày {% extends "layout.html" %} {% block body %} Body content goes here! {% endblock body %}5, đây là những gì chúng tôi sẽ nhận được
Tôi thích mẫu kế thừa mẫu của Jinja, nhưng việc thiếu câu lệnh bao gồm có thể dễ dàng dẫn đến các mẫu gốc khổng lồ Rất may, tôi đã tìm thấy một cách giải quyết đầy đủ cho việc thiếu câu lệnh bao gồm. Jinja cho phép bạn xác định, về cơ bản là các chức năng được sử dụng trong các mẫu để hiển thị nội dung nào đó. Tôi đã xác định một macro có tên là {% extends "layout.html" %} {% block body %} Body content goes here! {% endblock body %}7 chỉ trả về HTML cho điều hướng. Tôi đã làm điều tương tự cho {% extends "layout.html" %} {% block body %} Body content goes here! {% endblock body %}8, {% extends "layout.html" %} {% block body %} Body content goes here! {% endblock body %}9 và bất kỳ phần nào khác được lặp lại trên toàn bộ trang web. Lấy chân trang của chúng tôi, ví dụ {% nguyên %} {% macro footer() %} {% endmacro %} {% rút lại %} Sau đó, từ 0, tôi có thể gọi macro chân trang. Flask yêu cầu sử dụng bộ lọc 1 nếu bạn muốn hiển thị chuỗi trả về. Do đó, macro 2 có thể được gọi từ macro 3 mà không cần chỉ định 4. Nhưng vì 0 là thứ đang được hiển thị trực tiếp, nên chúng tôi cần chỉ định 1 mỗi khi chúng tôi gọi macro Vì vậy, 0 cuối cùng trông giống như {% nguyên %} {% from "sections" import meta_and_css, nav, javascripts, footer %} {{ meta_and_css(g, title)|safe }} {% rút lại %} Điều này không lý tưởng lắm, nhưng nó đã hoạt động; Là 'Dũng cảm'Flask không phải lúc nào cũng có giải pháp vượt trội cho vấn đề này. Trong thực tế, nó hiếm khi làm. Tuy nhiên, Flask đã cung cấp cho tôi tất cả các công cụ cần thiết để tạo ra bất cứ thứ gì tôi muốn. Theo một cách nào đó, tôi cảm thấy rằng chính Flask đang nói với tôi rằng "Joseph, bạn đủ thông minh để tự triển khai chức năng X. dũng cảm một lần. " Đôi khi phát minh lại bánh xe là một bài tập bổ ích Biểu mẫu liên hệPhương pháp được đề xuất để xử lý các biểu mẫu trong Flask là tiện ích mở rộng Flask-WTF. Flask-WTF có nhiều , nhưng nó không bao gồm xác thực số điện thoại. Không có gì to tát, bất kỳ thư viện biểu mẫu nào đáng giá đều có phương tiện để xác định các chức năng xác thực tùy chỉnh. WTForms trên thực tế có một cơ chế để triển khai các trình xác thực tùy chỉnh, nhưng tôi không thấy các ví dụ của chúng rất bắt mắt def length(min=-1, max=-1): message = 'Must be between %d and %d characters long.' % (min, max) def _length(form, field): l = field.data and len(field.data) or 0 if l < min or max != -1 and l > max: raise ValidationError(message) return _length class MyForm(Form): name = TextField('Name', [Required(), length(max=50)]) Do đó, tôi đã sử dụng Flask-WTF để thu thập dữ liệu từ các trường biểu mẫu, nhưng tôi đã triển khai mô-đun xác thực của riêng mình, việc này chỉ mất khoảng một giờ Việc gửi email thực tế được xử lý dễ dàng với mô-đun 8 tích hợp sẵn của Python và Gmail BlogTạo một blog đã trở thành "Xin chào, Thế giới" của các khung ứng dụng web. Mặc dù phần mềm viết blog Python tồn tại, nhưng có vẻ như sẽ mất nhiều thời gian hơn để tích hợp một nền tảng viết blog hiện có vào dự án Flask của tôi hơn là chỉ triển khai nền tảng viết blog của riêng tôi Trong khoảng một năm qua, tôi đã mong mỏi có một nền tảng viết blog dựa trên hệ thống tệp. Viết bài của tôi trong VIM + Markdown thú vị hơn nhiều so với viết HTML trong VIM, chuyển HTML sang Wordpress, xem trước HTML, đảm bảo định dạng đúng và các bước khó chịu khác Có một vài điều cụ thể tôi cần phải hoàn thành với blog
Không cần tạo nguồn cấp dữ liệu RSS, điều duy nhất tôi cần làm là định tuyến 9 tới một hàm cố gắng hiển thị mẫu có tên {% macro footer() %} {% endmacro %}0 và trả về 404 nếu không tìm thấy mẫu đó. Tuy nhiên, yêu cầu RSS buộc tôi phải suy nghĩ về cách lưu trữ dữ liệu meta cho mỗi bài đăng Tôi quyết định chọn một cấu trúc khá đơn giản, mặc dù không đẹp hay thông minh nhưng cũng đủ tốt cho tôi. Tôi tạo một thư mục trong {% macro footer() %} {% endmacro %}1 có tên là {% macro footer() %} {% endmacro %}2. Trong thư mục đó, tôi tạo hai tệp. {% macro footer() %} {% endmacro %}3 và {% macro footer() %} {% endmacro %}4. {% macro footer() %} {% endmacro %}3 chỉ chứa một vài biến cho siêu dữ liệu (ngày đăng, đoạn trích, v.v.) và nội dung. html có nội dung bài đăng Để tránh phải phân tích tất cả các tệp siêu dữ liệu để tìm ra thứ tự của các bài đăng cho nguồn cấp RSS, tôi chỉ cần thêm tên thư mục vào đầu tệp có tên là {% macro footer() %} {% endmacro %}6. Một lần nữa, không phải là thứ đẹp nhất trên thế giới nhưng đó là một hệ thống mà tôi thấy dễ hiểu và dễ làm việc Nguồn cấp dữ liệu RSS và phân trang blog được xử lý trong cùng một bước. Tôi chạy tập lệnh có tên là {% macro footer() %} {% endmacro %}7 để tạo tệp rss xml và tệp phân trang. Sử dụng các tệp tĩnh được tạo bởi tập lệnh {% macro footer() %} {% endmacro %}8 (đọc tập lệnh {% macro footer() %} {% endmacro %}6 đã đề cập trước đó) để phân trang có ý nghĩa vì cách phân trang chỉ thay đổi bất cứ khi nào tôi cập nhật/tạo một câu chuyện Nhập bài đăng trên blog của tôiĐể nhập các bài đăng Wordpress của tôi vào cấu trúc mới này, tất cả những gì tôi phải làm là phân tích cú pháp tệp xml xuất của Wordpress bằng PyQuery và tạo các tệp có chức năng thư viện chuẩn. Tôi không bận tâm chuyển đổi các bài đăng từ Wordpress sang Markdown, vì vậy tất cả các bài đăng cũ bạn xem qua trong nguồn sẽ có HTML bình thường Rắc rối về cấu trúcMột trong những rắc rối lớn nhất mà tôi gặp phải trong suốt quá trình phát triển trang web là làm thế nào để nhập mọi thứ vào các tệp cụ thể. Câu trả lời StackOverflow này mô tả các bước cần thiết để nhập mô-đun trong thư mục cha/anh chị em khi chạy tập lệnh trực tiếp. Do đó, bất kỳ tập lệnh nào cần quyền truy cập vào đối tượng {% from "sections" import meta_and_css, nav, javascripts, footer %} {{ meta_and_css(g, title)|safe }}0 (chứa nhiều phương thức và thuộc tính quan trọng về phiên bản ứng dụng), tôi phải chạy {% from "sections" import meta_and_css, nav, javascripts, footer %} {{ meta_and_css(g, title)|safe }}1 hoặc chỉ cần di chuyển {% macro footer() %} {% endmacro %}7 vào cùng thư mục với {% from "sections" import meta_and_css, nav, javascripts, footer %} {{ meta_and_css(g, title)|safe }}3, điều này sẽ cho phép tôi . Tôi đã chọn cái sau vì sự lười biếng tuyệt đối, mặc dù tôi không đặc biệt hạnh phúc khi phải đưa ra lựa chọn như vậy. Tôi nên lưu ý rằng đây không phải là sự cố cụ thể của Flask mà là sự cố Python Môi trường phát triển vs sản xuấtTrong quá trình phát triển, tất cả nội dung được cung cấp từ các tệp tĩnh. Trong sản xuất, tất cả tài sản được phục vụ từ S3. Môi trường được đặt bởi một env-var có tên là {% from "sections" import meta_and_css, nav, javascripts, footer %} {{ meta_and_css(g, title)|safe }}5. Tôi cần một cách để cho các mẫu của mình biết "Này, bạn đang ở trong môi trường sản xuất, bạn nên liên kết với các tệp S3 thay vì các tệp tĩnh. ". Tôi quyết định tận dụng đối tượng {% from "sections" import meta_and_css, nav, javascripts, footer %} {{ meta_and_css(g, title)|safe }}6 của Flask, một đối tượng toàn cục tồn tại trong bối cảnh yêu cầu. Bạn có thể tự do điền vào đó bất cứ thứ gì bạn muốn. Tôi đã tạo và sử dụng tài sản {% from "sections" import meta_and_css, nav, javascripts, footer %} {{ meta_and_css(g, title)|safe }}7 Mặc dù điều này hoàn toàn phù hợp với nhu cầu của tôi, nhưng nó khiến các mẫu của tôi trông kém đẹp hơn một chút. Bất cứ khi nào tôi muốn gọi một macro tìm kiếm thuộc tính {% from "sections" import meta_and_css, nav, javascripts, footer %} {{ meta_and_css(g, title)|safe }}7, tôi phải chuyển {% from "sections" import meta_and_css, nav, javascripts, footer %} {{ meta_and_css(g, title)|safe }}6 cho nó. Ví dụ: đây là định nghĩa của macro def length(min=-1, max=-1): message = 'Must be between %d and %d characters long.' % (min, max) def _length(form, field): l = field.data and len(field.data) or 0 if l < min or max != -1 and l > max: raise ValidationError(message) return _length class MyForm(Form): name = TextField('Name', [Required(), length(max=50)])0, một chức năng được sử dụng để hiển thị hình ảnh trên trang web {% nguyên %} {% macro img(g, file, alt="", class="") %} {% endmacro %} {% rút lại %} Một ví dụ gọi đến macro. {% nguyên %} {{img(g, "pointer.png", "", "pointer")|safe }} {% rút lại %} Nó dài dòng hơn những gì tôi thực sự thích, nhưng nó hoàn thành công việc Phát trực tiếp với Nginx và uWSGIBây giờ dự án của tôi đã hoàn thành khá nhiều, đã đến lúc đưa các tệp lên VPS Linode của tôi và giới thiệu dự án của tôi với mọi người. Tôi quyết định sử dụng Nginx với uWSGI, đơn giản vì cặp đôi này đã là chủ đề của nhiều hướng dẫn. Bản thân Flask có tài liệu về uWSGI. Tuy nhiên, tôi thấy các phần của tài liệu không đầy đủ Từ tài liệu # Given a flask application in myapp.py, use the following command: $ uwsgi -s /tmp/uwsgi.sock --module myapp --callable app Nếu bạn muốn đưa một dự án lên một máy chủ trực tiếp, không có cách nào bạn phải làm nhiều việc như vậy. uWSGI có các tệp cấu hình ini mà tôi đã tận dụng tối đa. Bây giờ, thay vì thực hiện một lệnh dài dòng từ trình bao, tôi có thể thực hiện một cách đơn giản $ uwsgi uwsgi.ini def length(min=-1, max=-1): message = 'Must be between %d and %d characters long.' % (min, max) def _length(form, field): l = field.data and len(field.data) or 0 if l < min or max != -1 and l > max: raise ValidationError(message) return _length class MyForm(Form): name = TextField('Name', [Required(), length(max=50)])1 của tôi như sau {% extends "layout.html" %} {% block body %} Body content goes here! {% endblock body %}0 Bây giờ cấu hình uWSGI của tôi nằm dưới sự kiểm soát phiên bản với phần còn lại của dự án của tôi Đây là một lời giải thích cho các thông số
Bây giờ, đối với các phần cấu hình nginx của tôi có liên quan đến uWSGI {% extends "layout.html" %} {% block body %} Body content goes here! {% endblock body %}1 Những việc CẦN LÀM còn lạiTôi cảm thấy mình đã làm đủ để xứng đáng loại bỏ trang PHP/Wordpress của mình và đặt trang Flask vào vị trí của nó. Mặc dù vậy, vẫn còn khá nhiều việc phải làm
Số lần hiển thị tổng thểNhìn chung, tôi khá hài lòng với Flask. Phần lớn, nó không theo cách của bạn và cho phép bạn xây dựng mọi thứ theo cách bạn muốn xây dựng chúng. Do đó, cấu trúc dự án của bạn có thể cẩu thả (đặc biệt là khi mới học Flask), nhưng đảm bảo bạn sẽ hiểu cách thức và lý do mọi thứ hoạt động Tôi có thể sử dụng Jinja trong HTML không?Tóm tắt. Mẫu Jinja chỉ đơn giản là một tệp văn bản. Jinja có thể tạo bất kỳ định dạng dựa trên văn bản nào (HTML, XML, CSV, LaTeX, v.v. ) . Mẫu Jinja không cần phải có phần mở rộng cụ thể. . html,. xml hoặc bất kỳ tiện ích mở rộng nào khác đều được.
Jinja trong HTML là gì?Jinja là công cụ mẫu web dành cho ngôn ngữ lập trình Python . Nó được tạo bởi Armin Ronacher và được cấp phép theo Giấy phép BSD. Jinja tương tự như công cụ mẫu Django nhưng cung cấp các biểu thức giống như Python trong khi đảm bảo rằng các mẫu được đánh giá trong hộp cát.
Jinja có thoát khỏi HTML không?Khi bật tính năng thoát tự động, Jinja2 sẽ lọc các chuỗi đầu vào để thoát mọi nội dung HTML được gửi qua các biến mẫu . Nếu không thoát đầu vào HTML, ứng dụng sẽ dễ bị tấn công Cross Site Scripting (XSS). Thật không may, autoescaping là Sai theo mặc định.
Tôi có thể sử dụng HTML trong Flask không?Khung bình đã được viết theo cách để nó tìm các tệp mẫu HTML trong một thư mục có tên là mẫu . Vì vậy, bạn nên tạo một thư mục trống như vậy và sau đó đặt tất cả các mẫu HTML vào đó. |