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

[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 đầu

Nhiệ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

  • Làm thế nào để tôi thực sự khởi động máy chủ?
  • Các mẫu của tôi đi đâu?
  • Tài sản tĩnh của tôi đi đâu?
  • Làm cách nào để truy xuất nội dung của tôi từ bên trong các mẫu?
  • Làm cách nào để định tuyến các yêu cầu?

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 %}



  My Website 
  
  
{% block body %}{% endblock body %}

{% 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



  My Website 
  
  
Body content goes here!

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ừ



  My Website 
  
  
Body content goes here!
0, tôi có thể gọi macro chân trang. Flask yêu cầu sử dụng bộ lọc


  My Website 
  
  
Body content goes here!
1 nếu bạn muốn hiển thị chuỗi trả về. Do đó, macro


  My Website 
  
  
Body content goes here!
2 có thể được gọi từ macro


  My Website 
  
  
Body content goes here!
3 mà không cần chỉ định


  My Website 
  
  
Body content goes here!
4. Nhưng vì


  My Website 
  
  
Body content goes here!
0 là thứ đang được hiển thị trực tiếp, nên chúng tôi cần chỉ định


  My Website 
  
  
Body content goes here!
1 mỗi khi chúng tôi gọi macro

Vì vậy,



  My Website 
  
  
Body content goes here!
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 }}
  
{{ nav(g)|safe }}
{% block body %}{% endblock body %}
{{ footer()|safe }}
{{ javascripts(g)|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



  My Website 
  
  
Body content goes here!
8 tích hợp sẵn của Python và Gmail

Blog

Tạ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ả năng tạo nguồn cấp dữ liệu RSS
  • URL của các bài đăng trên blog phải giống như trước đây
  • phân trang

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



  My Website 
  
  
Body content goes here!
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úc

Mộ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 }}
  
{{ nav(g)|safe }}
{% block body %}{% endblock body %}
{{ footer()|safe }}
{{ javascripts(g)|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 }}
  
{{ nav(g)|safe }}
{% block body %}{% endblock body %}
{{ footer()|safe }}
{{ javascripts(g)|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 }}
  
{{ nav(g)|safe }}
{% block body %}{% endblock body %}
{{ footer()|safe }}
{{ javascripts(g)|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ất

Trong 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 }}
  
{{ nav(g)|safe }}
{% block body %}{% endblock body %}
{{ footer()|safe }}
{{ javascripts(g)|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 }}
  
{{ nav(g)|safe }}
{% block body %}{% endblock body %}
{{ footer()|safe }}
{{ javascripts(g)|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 }}
  
{{ nav(g)|safe }}
{% block body %}{% endblock body %}
{{ footer()|safe }}
{{ javascripts(g)|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 }}
  
{{ nav(g)|safe }}
{% block body %}{% endblock body %}
{{ footer()|safe }}
{{ javascripts(g)|safe }}
7, tôi phải chuyển
{% from "sections" import meta_and_css, nav, javascripts, footer %}


  {{ meta_and_css(g, title)|safe }}
  
{{ nav(g)|safe }}
{% block body %}{% endblock body %}
{{ footer()|safe }}
{{ javascripts(g)|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à uWSGI

Bâ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ố

  • dự án. Tên mô-đun mà bạn gọi là
    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)])
    
    2
  • quỷ hóa. Nếu bạn muốn daemon hóa. Vì lý do nào đó, bạn phải chỉ định đường dẫn tệp nhật ký nếu không uWSGI sẽ đẩy mọi thứ xuống
    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)])
    
    3.
    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)])
    
    4 không hiệu quả với tôi
  • bậc thầy. Boolean cho biết nếu bạn muốn có một quy trình tổng thể. Các quy trình tổng thể giúp quản lý uwsgi dễ dàng hơn nhiều
  • chdir. Thay đổi thư mục. Về cơ bản, cho phép bạn giữ các tham số như "dự án" và virtualenv so với đường dẫn được cung cấp cho chdir
  • ổ cắm. Đường dẫn ổ cắm Unix hoặc thông tin ổ cắm TCP
  • wsgi. %(mô-đun chứa ứng dụng). ứng dụng
  • virtualenv. Đường dẫn đến virtualenv cho dự án
  • pidfile. Tệp pid quy trình chính sẽ được ghi ở đâu
  • cảm ứng tải lại. Chạm vào tệp này sẽ khiến các quy trình tải lại (thuận tiện. )
  • quy trình. Bạn muốn chạy bao nhiêu quy trình (không bao gồm quy trình chính)
  • procname-tiền tố. Tiền tố tên quy trình. Hữu ích cho
    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)])
    
    5

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ại

Tô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

  • Tôi dự định xuất các nhận xét Wordpress của mình sang Disqus. Tôi thích tương tác với những người đọc bài viết của tôi và tôi muốn giữ lại những nhận xét mà tôi đã nhận được

  • Tôi đã xoay sở để phá vỡ một số liên kết. Đặc biệt, tôi đã phá vỡ các liên kết đến các tệp php mà tôi đã ngu ngốc sử dụng để giới thiệu một số plugin jQuery của mình

  • Using prettify for syntax highlighting means I have to still use

     tags in my documents, since the script requires a class of "prettyprint" on those tags. I'll either adjust prettyprint js and styles myself, find an alternative syntax highlighter, or do some processing of the markup to append the "prettyprint" class whenever it finds the 
     tag.

  • Vẫn cần thiết lập triển khai git. Tôi hiện chỉ lấy từ repo bitbucket riêng trên máy chủ của mình

  • Tôi cần tự động hóa quy trình xây dựng của mình. Một tập lệnh bash duy nhất sẽ nối tất cả các tệp CSS/JS của tôi, chạy YUICompressor và tải các tệp lên S3

  • Tôi thực sự cần triển khai thẻ mô tả meta cho bài đăng của mình. nhưng điều đó sẽ yêu cầu tôi phải thực sự viết chúng

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 đó.