整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          初識 flask 中的模板語言-Jinja2

          初識 flask 中的模板語言-Jinja2

          inja2是一個流行的Python模板引擎,它可以幫助開發人員更加高效地構建Web應用程序。在本文中,我們將介紹Jinja2的基礎知識和使用方法,并通過編程示例來演示其實際應用。

          Jinja2是一個基于Python的模板引擎,它使用簡單、靈活性高,適用于各種Web應用程序的開發。Jinja2提供了類似于HTML的模板語言,可以動態地生成HTML頁面,并支持循環、條件判斷、變量替換等常用操作。在Jinja2中,我們可以使用{{}}標記表示需要動態生成的內容,并使用if語句和for循環等語句實現條件判斷和循環操作。

          下面,讓我們通過一個簡單的示例來了解Jinja2的使用。假設我們需要創建一個Web應用程序,顯示一個包含用戶信息的動態頁面。首先,我們需要定義一個包含用戶信息的Python字典,例如:

          users=[
              {'name': 'Alice', 'age': 25},
              {'name': 'Bob', 'age': 30},
              {'name': 'Charlie', 'age': 35}
          ]
          

          接著,我們需要創建一個Jinja2模板,用于生成包含用戶信息的HTML頁面。在模板中,我們可以使用for循環語句遍歷用戶列表,并使用{{}}標記表示需要動態生成的內容。例如,我們可以創建一個名為user.html的模板文件,內容如下:

          <!DOCTYPE html>
          <html>
          <head>
              <title>User List</title>
          </head>
          <body>
              <h1>User List</h1>
              <ul>
                  {% for user in users %}
                  <li>{{ user.name }} - {{ user.age }}</li>
                  {% endfor %}
              </ul>
          </body>
          </html>
          

          在模板中,我們使用{% for %}和{% endfor %}標記實現循環操作,并使用{{ user.name }}和{{ user.age }}標記表示用戶的姓名和年齡。接著,我們可以通過render_template()函數將模板與路由函數關聯起來,實現動態Web頁面的生成。例如,我們可以創建一個名為app.py的Python文件,內容如下:

          from flask import Flask, render_template
          
          app=Flask(__name__)
          
          users=[
              {'name': 'Alice', 'age': 25},
              {'name': 'Bob', 'age': 30},
              {'name': 'Charlie', 'age': 35}
          ]
          
          @app.route('/')
          def index():
              return render_template('user.html', users=users)
          
          if __name__=='__main__':
              app.run()
          

          在該文件中,我們首先導入Flask和render_template函數,并創建一個名為app的Flask應用程序。接著,我們定義一個名為users的列表,包含三個用戶的信息。最后,我們定義一個名為index的路由函數,用于處理用戶的請求。在該函數中,我們使用render_template()函數將user.html模板與路由函數關聯起來,并將用戶列表傳遞給模板。最后,我們通過app.run()函數啟動Flask應用程序,實現Web應用程序的運行。

          總之,Jinja2是一個強大的Python模板引擎,可以幫助開發人員更加高效地構建Web應用程序。通過掌握其基礎知識和使用方法,我們可以輕松地實現各種復雜的Web頁面和功能。

          cJinja 是一個使用cpp編寫的輕量html模版解析庫,依賴 ejson 來實現模版的數據替換(在jinja中稱為context,上下文)。模版的語法基本與django jinja一致,功能還算豐富。源碼僅有700行,適合學習,覺得不錯的點個star吧。

          (該程序為 https://github.com/HuangHongkai/tinyserver 中的一個模塊)

          編譯

          使用cmake來編譯,windows和linux下均可編譯。推薦使用clion作為IDE。

          編譯成功后在build目錄下會有libcjinja.a和cjinja_test.exe這2個文件。libcjinja.a是靜態庫,cjinja_test.exe是一個簡單的測試程序。

          運行測試程序后會出現output.html(該文件是tmp.html解析后的結果。)

          已經完成的功能

          • 變量,例如 {{ var }}
          • 變量索引訪問,例如 {{ var.var2 }} {{ var[2] }} {{ var[2].key.value[2] }},其中**[]** 表示對數組(類似python的list)進行索引, . 表示對object進行索引(類似與python的dict)
          • 表達式計算(包括字符串拼接) ,例如{{ 1*1+2-3*var }} {{ 1+1*2-3/4 }} {{ "asdfsf"+var }}
          • for-endfor對列表進行迭代, 例如 {% for var in list %} {% endfor %}
          • for-endfor對對象進行迭代,例如 {% for key,value in object %} {% endfor %} 或者 {% for key in object %}{% endfor %} 或者 {% for ,value in object %} {% endfor %}
          • if-else-endif 語句, 其中if的條件支持四則運算,簡單的比較(!===)等,例如 {% if 1+1==2 %}aaa{% else %}bbb{%endif %}
          • 模版包含,嵌套其他的模版文件{% include 'other.html' %}
          • 模版語法錯誤提示

          需要注意,表達式之間不能含有空格,例如{{ 1 + 1 }}是非法的,而{{ 1+1 }}是合法的。

          使用方法

          1. 變量和變量索引

          簡單的例子如下,

          HtmlTemplate html("username:{{ username }}\n"
           "parm.list[1][2]: {{parm.list[1][2] }} \n"
           "parm.key: {{ parm.key }}",
           1); // 參數1表示傳入的是模版字符串,0表示傳入的是文件名,默認為0
          JSONObject obj={
           {"username", 1234},
           {"parm", {
           {"key", "cde"},
           {"list", {1, {1,2.3, "abcd"}, "hahaha"}},
           }}
          };
          html.setValue(obj);
          cout << html.render() << endl << endl;
          /* 運行后打印如下
          username:1234
          parm.list[1]: abcd 
          parm.key: cde
          */
          

          HtmlTemplate是一個庫的主要類,構造函數為

          explicit HtmlTemplate(const string& str, int flag=0); // flag=0是str表示文件路徑,不為0是表示傳入的模版字符串

          其中str參數為字符串,可以表示html模板原始串,也可也表示為文件的路徑,flag默認為0。

          setValue 方法表示傳入數據給模版對象。

          render() 方法表示將模版解析成字符串。

          JSONObject來源于 ejson 庫,用來模擬python的dict,構造函數也比較容易看懂。

          2. 列表迭代

          HtmlTemplate html("{% for x in list %}{{ x }}\n{%endfor%}"
           "此時x已經是臨時變量了,不可以在打印了 {{x}}\n"
           , 1);
          JSONObject obj=OBJECT(
           KEYVALUE("list", LIST(1,2,3,4,5))
          );
          cout << html.setValue(obj).render() << endl << endl;
          /*運行后輸出如下
          1
          2
          3
          4
          5
          此時x已經是臨時變量了,不可以在打印了 
          */
          

          注意到在迭代過程中x是作為臨時變量,在外部的話是無法打印出來的。

          3. 字典迭代

          HtmlTemplate html("{% for key in dict %}迭代1: 字典的key值為 {{ key }}\n{% endfor %}"
           "{% for key,value in dict %}迭代2: 字典的key值為 {{ key }}, value值為 {{ value}}\n{% endfor %}"
           "{% for ,value in dict %}迭代3: 字典的value值為 {{ value }}\n{% endfor %}", 1);
          JSONObject obj=OBJECT(
           KEYVALUE("dict", OBJECT(
           KEYVALUE("key1", "value1"),
           KEYVALUE("key2", 1234),
           KEYVALUE("key3", nullptr),
           ))
          );
          cout << html.setValue(obj).render() << endl << endl;
          /*運行后輸出
          迭代1: 字典的key值為 key1
          迭代1: 字典的key值為 key2
          迭代1: 字典的key值為 key3
          迭代2: 字典的key值為 key1, value值為 value1
          迭代2: 字典的key值為 key2, value值為 1234
          迭代2: 字典的key值為 key3, value值為 null
          迭代3: 字典的value值為 value1
          迭代3: 字典的value值為 1234
          迭代3: 字典的value值為 null
          */
          

          4. 字符串拼接與表達式計算

          HtmlTemplate html("{{ a+b+c+\"444\" }}\n"
           "{{x}} * {{y}} + 2 * 3 - 4 / {{x}}={{ x*y+2*3-4/x }}\n",
           1);
          JSONObject obj=OBJECT(
           KEYVALUE("a", "111"),
           KEYVALUE("b", "222"),
           KEYVALUE("c", "333"),
           KEYVALUE("x", 12),
           KEYVALUE("y", 34)
           );
          cout << html.setValue(obj).render() << endl << endl;
          /*運行后輸出
          111222333444
          12 * 34 + 2 * 3 - 4 / 12=413.667
          */
          

          5. if-else-endif語句

          HtmlTemplate html("{% if 1==1 %} 1==1 成立 {% else %} 1==1不成立 {%endif %}\n"
           "{% if !x %} x為空 {% else %} x不為空 {%endif %}\n"
           "{% if x==2 %} x==2 成立 {% endif %}\n"
           "{% if x+1!=2 %} x+1!=2 成立 {% endif %}\n"
           "{% if x<3 %} x<3 成立 {% endif %}\n"
           "{% if x>1 %} x>1 成立 {% endif %}\n"
           "{% if str==\"abcd\" %} str為abcd {% endif %}\n"
           "{% if 1 %} 常量表達式1 {% endif %}\n"
           "{% if 0 %} 常量表達式0,此處不會輸出 {%endif%}", 1);
          JSONObject obj={
           {"x", 2},
           {"str", "abcd"}
          };
          cout << html.setValue(obj).render() << endl;
          /*運行后輸出
           1==1 成立 
           x不為空 
           x==2 成立 
           x+1!=2 成立 
           x<3 成立 
           x>1 成立 
           str為abcd 
           常量表達式1 
          */
          

          6.for與if嵌套使用

           HtmlTemplate html("{%for x in list%}"
           "{%if x %}"
           "{% for y in list2%}"
           "{{x}} * {{y}}={{ x*y }}\n"
           "{% endfor %}"
           "{% else %}"
           "x的值為空\n"
           "{%endif%}"
           "{% endfor%}", 1);
          JSONObject obj=OBJECT(
           KEYVALUE("list", LIST(1,2,3,4,5)),
           KEYVALUE("list2", LIST(1,2,3)),
          );
          cout << html.setValue(obj).render() << endl << endl;
          /*運行后輸出
          1 * 1=1
          1 * 2=2
          1 * 3=3
          2 * 1=2
          2 * 2=4
          2 * 3=6
          3 * 1=3
          3 * 2=6
          3 * 3=9
          4 * 1=4
          4 * 2=8
          4 * 3=12
          5 * 1=5
          5 * 2=10
          5 * 3=15
          */
          

          7.模版文件作為輸出

          HtmlTemplate html("tmpl.html");
          JSONObject context=OBJECT(
           ...
          );
          FILE* f=fopen("output.html", "w"); // 寫入到文件中
          string&& str=html.setValue(context).render();
          fwrite(str.c_str(), 1, str.size(), f);
          fclose(f);
          /*運行后,代開當前目錄的tmpl.html文件作為輸入,輸出文件為output.html*/
          /*如果tmpl.html不存在則拋出異常*/
          

          8. 異常處理

          HtmlTemplate html("{% if 1 %} xxx ", 1);
          // 不傳入context
          try {
           cout << html.render() << endl;
          } catch(exception& e) {
           cerr << e.what() << endl;
          }
          cout << endl;
          

          運行后終端上打印如下,

          會提示異常的類名,異常文件所在位置,代碼行數,以及一些錯誤的信息。

          討論

          1. 實現一個簡單的表達式計算器用什么方法比較好?(例如 {{ 2.3*3+4/5*x }} 這類表達式)

          我分享一下我自己的方法,有什么更好的方法一起討論一下。

          • 第一步,先把數據和符號提取出來放入到數組中,輸入類型全部設為double。例如上面那個表達式,符號提取出來是{*, /, *}, 數據提取出來是{2.3, 3, 4, 5, x}
          • 這一步位于__parse_var這個函數,比較簡單不詳細討論。
          • 第二步,先計算乘除法,結果放入棧中,在對棧中元素計算加減法(按照我們平常計算表達式的思路先乘除后加減),這一步實現如下(其中運用到C語言的宏和C++11的匿名函數)
          double cJinja::HtmlTemplate::calculator(vector<any>& number, vector<char>& op) {
           // 例如下表達式會成為
           // 1 - 2 - 3 + 2 *3 * 4 - 4*5
           // vector<char> op={ '-', '-', '+', '*', '*', '-', '*' };
           // vector<any> number={ 1, 2, 3, 2, 3, 4, 4, 5 };
           if (number.size() !=op.size() + 1)
           throwException(TemplateParseException, "運算符號數和操作數不匹配");
           /* 定義計算器的內部函數 */
           auto calc=[](any& var1, double var2, char op) -> double{
           // var2 + var1
           // var2 * var1
           // var2 - var1
           // var2 / var1
           // 注意順序
          #define CALC(op2) \
           if(#op2[0]==op) { \
           if (var1.type()==typeid(int)) \
           return var2 op2 static_cast<double>(any_cast<int>(var1)); \
           else if (var1.type()==typeid(float)) \
           return var2 op2 static_cast<double>(any_cast<float>(var1)) ; \
           else if (var1.type()==typeid(double)) \
           return var2 op2 static_cast<double>(any_cast<double>(var1)) ; \
           }
           CALC(+);
           CALC(-);
           CALC(*);
           CALC(/);
           throwException(TemplateParseException, "不允許對空指針進行運算");
          #undef CALC
           };
           vector<double> num_stack; // 計算中間結果存儲棧
           num_stack.push_back(calc(number[0], 0, '+')); // 獲取值 number[i+1] + 0 (加法運算零元為0,乘法運算零元為1)
           /* 計算 * / 法*/
           for (size_t i=0; i < op.size(); i++) {
           if (op[i]=='+' || op[i]=='-') {
           num_stack.push_back(calc(number[i + 1], 0, '+')); // number[i+1] + 0
           }
           else if (op[i]=='*' || op[i]=='/') {
           double var1=num_stack.back(); num_stack.pop_back();
           num_stack.push_back(calc(number[i + 1], var1, op[i])); // var1/number[i+1] 或者是 var1/number[i+1]
           } else
           throwException(TemplateParseException, str_format("非法操作符 %d", op[i]));
           }
           /* 計算 + - 法*/
           double result=num_stack[0];
           size_t i=1;
           for (auto& ch : op) {
           if (ch=='+') {
           result +=num_stack[i++];
           } else if(ch=='-') {
           result -=num_stack[i++];
           }
           }
           return result;
          }
          

          2. 拋出異常包含更多的信息

          我定義了一個throwException宏,如下

          #define throwException(Exception, ...) { \
           std::cerr << "[" << #Exception << "] : FILE: " << string(__FILE__).substr(string(__FILE__).find_last_of('/') + 1) << " LINE: " << __LINE__ << " FUNCTION: " <<__FUNCTION__ << std::endl; \
           throw Exception(__VA_ARGS__); \
           }
          

          其中__FILE__ 為文件名,__LINE__ 為當前代碼行數,這些都是C中的內置宏,__VA_ARGS__是可變參數,對應于宏函數參數中的....

          inja2提供了一系列的控制語句,用于在模板中實現邏輯控制。以下是Jinja2中常用的控制語句:

          條件語句:

          {% if %}: 檢查條件是否為真,如果為真則執行大括號內的代碼。

          {% elif %}: 如果前面的條件為假,則檢查這個條件。

          {% else %}: 如果前面的所有條件都為假,則執行這個代碼塊。

          {% endif %}: 結束if語句塊。

          示例:

          {% if user %}

          歡迎, {{ user.name }}

          {% elif guest %}

          你好, 匿名用戶

          {% else %}

          請登錄

          {% endif %}


          循環語句:

          {% for %}: 遍歷序列或字典。

          {% endfor %}: 結束for循環。

          示例:

          {% for item in items %}

        1. {{ item }}
        2. {% endfor %}


          宏(Macros):

          {% macro %}: 定義一個可重用的代碼塊,類似于函數。

          {% endmacro %}: 結束宏定義。

          示例:

          {% macro render_item(item) %}

        3. {{ item }}
        4. {% endmacro %}

          {% for item in items %}

          {{ render_item(item) }}

          {% endfor %}


          包含(Include):

          {% include %}: 包含另一個模板文件的內容。

          示例:

          {% include 'partials/header.html' %}


          標簽控制:

          {% set %}: 設置一個變量。

          {% del %}: 刪除一個變量。

          示例:

          {% set my_var='Hello World' %}

          {{ my_var }}

          {% del my_var %}

          {# 此時my_var已被刪除 #}


          循環控制:

          {% break %}: 跳出當前循環。

          {% continue %}: 跳過當前循環的剩余部分,繼續下一次迭代。

          示例:

          {% for item in items %}

          {% if item=='特定值' %}

          {% continue %}

          {% endif %}

        5. {{ item }}
        6. {% endfor %}


          注釋:

          {# #}: 在模板中添加注釋,注釋內容不會被渲染到最終的HTML中。

          示例:

          {# 這是一條注釋 #}


          這些控制語句使得Jinja2模板能夠靈活地實現復雜的邏輯控制,從而在不改變后端代碼的情況下,直接在模板層面進行數據展示的控制。


          主站蜘蛛池模板: 人妻体体内射精一区二区| 亚洲爆乳精品无码一区二区三区 | 亚洲AV无码一区二区三区网址| 蜜桃视频一区二区三区| 中文字幕人妻AV一区二区| 国产一区二区电影在线观看| 红桃AV一区二区三区在线无码AV| 久久精品国产一区二区电影| 色老板在线视频一区二区| 日韩精品无码久久一区二区三| 亚洲乱码av中文一区二区| 国产精品分类视频分类一区 | 日本精品一区二区在线播放| 综合久久一区二区三区| 国产伦理一区二区| 亚洲综合一区无码精品| 一区二区三区免费高清视频| 亚洲一区爱区精品无码| 国产福利一区二区| 91精品福利一区二区三区野战| 亚洲综合一区国产精品| 国产亚洲福利精品一区| 无码中文字幕一区二区三区| 国产精品一区二区久久不卡| 国产乱码精品一区二区三区四川人 | 国产成人欧美一区二区三区| 国产在线一区二区杨幂| 亚洲视频在线一区| 亚洲免费视频一区二区三区| tom影院亚洲国产一区二区| 日韩视频免费一区二区三区| 国产成人精品无码一区二区三区 | 男女久久久国产一区二区三区| 国产伦精品一区二区| 日韩精品无码一区二区视频| 福利一区二区视频| 精品国产区一区二区三区在线观看| 国产福利一区二区三区视频在线| 国模无码一区二区三区不卡| 国产日韩综合一区二区性色AV| 乱子伦一区二区三区|