2010-05-25 21 views
10

Ben kolayca şablon dosyalarının kendilerini içinden js ve css dosyaları belirtmek için izin şablon etiket kümesi yazmaya çalışıyorum. {% requires global.css %} satırlarında ve daha sonra istekte bulunan {% get_required_css %}.Django templatetag "işleme sırası"

Bu çoğunlukla çalışıyor, ancak birkaç sorun var. 'Zamanlama' sorunları ile başlayacağız.

Her şablon etiket/init arayıp render iki adımdan oluşur. Her çağrı/init herhangi bir işleme prosedürü çağrılmadan önce gerçekleşir. Tüm dosyaların, {% get_required_css %}'dan önce sıraya alınmasını garantilemek için, gerekli dosyaların listesini kendi aralarında başlatma/başlatma prosedürlerinde oluşturmam gerekir.

Yani, istek başına bir paket içine tüm dosyaları toplamak gerekir. context dict açıkçası bunun için bir yer, ama ne yazık ki, çağrı/init bağlam değişkenine erişim yok.

Bu anlam kazanıyor mu? Herkes bunun için bir yol görüyor (hack-y global request nesnesine başvurmadan)?

Bunları yerel bir dict'ta saklamak için başka bir olasılık olsa da, yine de bir şekilde {% start_requires %} etiketinin bir çeşit isteğine bağlı olması gerekir. Ama bu işi nasıl yapacağı konusunda hiçbir fikrim yok. Ben bir yol ile geldim

+0

Kısaca 'middleware' yeteneklerini kontrol ettikten sonra, oluşturulan html eklemek için bunu kullanmayı düşünüyorum. Bununla ilgili sorun, sorunsuz çalışabilmek için çeşitli statik sıkıştırma uygulamalarından herhangi birinin elde edilmesinin daha zor olmasıdır. –

+0

Birisi ilgilenirse, bu özel problem için oldukça zarif olmayan bir çözüm olan github üzerinde bir uygulama var - http://github.com/pappy74/django-requires_js_css. Jack'in aşağıdaki cevabı biraz benzer, ama güzel ve düzgün bir uygulama olarak paketlenmiş. –

cevap

2

bu daha uygun ihtiyaçları yapmak. Sunucuda biraz daha fazla yük olacaktır, ancak uygun önbellekleme, bunun çoğunu hafifletmeye yardımcı olabilir. Aşağıda, CSS'nin her yol için aynı olması durumunda çalışması gereken bir yolu özetledim. Tüm bu dosyaları dahil etmek için tek bir görünüm oluşturmanız gerekir, ancak bu yöntemi kullanarak CSS'nizi gerçekten optimize edebilirsiniz, böylece her sayfa için yalnızca bir CSS çağrısı yapabilirsiniz.

import md5 
class LoadCss(template.Node): 
    def __init__(self, tag_name, css): 
     self.css = css 
     self.tag_name = tag_name 
    def render(self, context): 
     request = context['request'] 
     md5key = md5.new(request.path).hexdigest() 
     if md5key not in request.session: 
      request.session[md5key] = list() 
     ## This assumes that this method is being called in the correct output order. 
     request.session[md5key].append(self.css) 
     return '<!-- Require %s -->' % self.css 
def do_load_css(parser, token): 
    tag_name, css = token.split_contents() 
    return LoadCss(tag_name, key) 
register.tag('requires', do_load_css) 

class IncludeCss(template.Node): 
    def __init__(self, tag_name): 
     self.tag_name = tag_name 
    def render(self, context): 
     request = context['request'] 
     md5key = md5.new(request.path).hexdigest() 
     return '<link rel="stylesheet" href="/path/to/css/view/%s">' % md5key 
def do_include_css(parser, token): 
    return IncludeCss(token) 
register.tag('get_required_css', do_include_css) 

views.py:

from django.conf import settings 
from django.views.decorators.cache import cache_page 
import os 

@cache_page(60 * 15) ## 15 Minute cache. 
def css_view(request, md5key): 
    css_requires = request.session.get(md5key, list()) 
    output = list() 
    for css in css_requires: 
     fname = os.path.join(settings.MEDIA_ROOT, 'css', css) ## Assumes MEDIA_ROOT/css/ is where the CSS files are. 
     f = open(fname, 'r') 
     output.append(f.read()) 
    HttpResponse(''.join(output), mimetype="text/css") 

Bu oturumda, sonra bağlamda CSS bilgileri depolamak ve bunu yapmak için önbelleğe alma ile (bir görünümden çıktı sunulmasına olanak tanır Daha hızlı). Bu elbette, biraz daha fazla sunucu yüküne sahip olacak.

sadece yolun daha üzerindeki CSS değişir gerekiyorsa

, o zaman sadece ihtiyaçlarını karşılamak için md5 satırları değiştirebilir. Tüm istek nesnesine ve içeriğe erişiminiz vardır, bu yüzden hemen hemen her şey orada olmalıdır.

Dikkat: oturum doldurulmadan önce tarayıcı CSS getirir eğer ikinci incelemede, bu bir yarış durumu neden olabilir. Django'nun bu şekilde çalıştığına inanmıyorum, ama şu anda bakmaktan hoşlanmıyorum.

+0

Bu şekilde başlangıçta nasıl uygulandım, ama sorun bir sipariş. Bununla birlikte, * 'get_required' öğesinin ayrıştırılmasından önce tüm 'gerektirir' öğelerinin ayrıştırıldığından emin olmalısınız.Bir içerme şablonu etiketinin kendisi bir css dosyası gerektirdiğinde bu özellikle belirgindir. Eğer dosyaları __init__ sırasında gerçekten ekleyebilirseniz, o konuyla ilgilenirsiniz. –

+0

Bunu yapmak için iç siparişe bağlı olmayan başka bir yol ekledim. Biraz kıvrımlı, ama işe yaramalı. –