1

我正在開發我的網站的移動版本,所以想到使用用戶代理作爲爲移動版和網頁版提供不同模板的標準。 我成功地從nginx讀取用戶代理信息並將其作爲頭傳遞給gunicorn服務器。基於django中的用戶代理的移動模板確保線程安全

然後我創建了一箇中間件,它讀取這個頭文件並更改設置文件中的templates目錄。這似乎最初工作,但後來我意識到有競爭狀況發生,因爲這種方法不是線程安全的。 (我應該事先想到它)。

所以我開始考慮其他的選擇。一種解決方案是覆蓋django的渲染方法,以包含基於請求頭的「dirs」參數。但後來我發現「dirs」參數已被棄用。以下是參考鏈接https://docs.djangoproject.com/en/1.9/_modules/django/shortcuts/#render 所以即使這不起作用。

另一種解決方案是針對移動設備和網絡使用不同的模板名稱並相應地加載它們。但我不想這樣做,並希望保持模板目錄結構完全相同的網絡和移動。

必須有一種方法來覆蓋模板目錄。如果在移動模板目錄中缺少這個模板,這將使我在Web版本的模板上回落。

任何建議如何實現這將是有益的。

這就是我的模板組織方式。

App1 
    templates 
     App1 
      index.html 
      catalog.html 
App2 
    templates 
     App2 
      about.html 

,並在項目目錄(而不是應用程序文件夾的一部分),有一個移動模板文件夾,其具有以下結構

mobile-templates 
    App1 
     index.html 
    App2 
     about.html 

感謝 阿努拉格

+0

如何修改'request'對象來添加目錄名?然後'render'可以通過附加路徑到這個'request.template_dir'變量來渲染文件。 – sudshekhar

+0

@SudhanshuShekhar - 即使我修改了請求對象,render函數將如何自動獲取目錄名稱?我也檢查了源代碼,並沒有發現render.template_dir被渲染函數使用。不知道我是否錯過了一些東西,請澄清。 如果您的意思是在我的渲染函數中預先追加目錄名稱,那麼在Web版本上回落將不起作用。 – Anurag

+0

我正在考慮類似於:'render(request,[「app/template/t_mobile.html」,「app/template/t.html」],context)'。您可以使用'request.template_dir'來決定是否添加't_mobile.html'作爲選項。 – sudshekhar

回答

1

這是我會怎麼安排我的模板:

  1. 使內部templates DIR兩個目錄 - mobiledesktop
  2. 保留mobile目錄中的手機模板和desktop中的桌面模板。

這樣你就不必重命名模板。


而這裏的我會怎樣使它們:

  1. 讀的User-Agent的中間件。
  2. request上設置名爲template_prefix的屬性,其值將爲mobiledesktop,具體取決於User-Agent。例如:

    def process_request(self, request): 
        # read user agent and determine if 
        # request is from mobile or desktop 
        # ... 
        if mobile_user_agent: 
         request.template_prefix = 'mobile' 
        else: 
         request.template_prefix = 'desktop' 
    
  3. 在您的看法,模板名稱前使用request.template_prefix。例如:

    def home(request): 
        ... 
        template = request.template_prefix + '/home.html' 
        return render(request, template) 
    

這將使從取決於價值template_prefix屬性要麼mobiledesktop迪爾斯模板。


UPDATE(根據問題編輯):

在你的模板是如何組織的展望,我應該這樣做:

  1. 中間件:

    只有設置針對移動請求的template_prefix

    def process_request(self, request): 
        if mobile_user_agent: 
         request.template_prefix = 'mobile-templates' 
        else: 
         request.template_prefix = '' # set an empty string 
    
  2. 瀏覽:

    使用os.path.join;趕上TemplateDoesNotExist異常。

    import os.path 
    from django.template.loader import get_template 
    from django.template.base import TemplateDoesNotExist 
    
    def index(request): 
        try: 
         template = os.path.join(request.template_prefix, 'App1/index.html') 
         get_template(template) 
        except TemplateDoesNotExist: 
         template = 'App1/index.html' 
    
        return render(request, template) 
    

我測試過這一點,它的工作原理。但在每個視圖中寫一個try...except塊似乎是多餘的。如果我想出更好的解決方案,我會更新。

+0

這將爲後備案例帶來錯誤,因爲與臺式機相比,移動模板將會非常少。如果找不到移動模板,它應該回退到桌面模板。 – Anurag

+0

@anurag在這種情況下,您只能在要呈現不同模板的視圖中使用'request.template_prefix'。如果該視圖沒有移動模板,請手動使用「桌面」前綴。更新了答案。 – xyres

+0

是的,但問題是我不知道模板是否存在。所以我將不得不檢查文件是否存在,或者在創建移動模板時修改我的渲染函數。 我能夠通過使用參數「dirs」來修改渲染函數,但因爲它不贊成我正在尋找合適的方法。無法理解爲什麼不推薦使用。 – Anurag

0

看來它不是現在開箱即可。如果你真的想遵循這個架構,你將不得不編寫你自己的定製加載器,並找出一種方法來傳遞請求/指示器,讓它知道它的移動請求。編寫加載器並不難(只要看到Django文件系統加載器,如果請求來自移動設備,循環遍歷所有templates_dirs併爲其添加適當的後綴,以便包含移動目錄)。

然而,我所看到的最大挑戰是能夠傳遞一個動態參數給它(表明這是一個移動請求)。您可以將此參數存儲在會話中,或者在將模板名稱傳遞給自定義渲染器之前修改模板名稱(渲染器將移除該指示器部分並獲取模板)。

+0

它不是遵循特定的體系結構,這更多的是我正在尋找適當解決方案的問題陳述。我可以創建加載器,但正如你所說的那樣,加載器方法無法訪問請求對象,因此傳遞動態參數是一種痛苦。 https://docs.djangoproject.com/en/1。9/ref/templates/api /#custom-loaders 在加載模板之前修改模板名稱,然後讀取它並撤銷之前完成的修改似乎更加令人困惑。 – Anurag

+0

看起來像一個普通的問題,不知道人們如何解決這個問題 – Anurag