2013-08-19 13 views
5

Chcę wygenerować czytelny dla człowieka kod HTML i CSS (odpowiednio wcięty) wstępnie przetworzony przez system szablonów Django dla mojej samodzielnej aplikacji.Właściwe wcięcie w szablonach Django (bez łatania małp)?

Zmodyfikowałem metodę renderowania z klasy NodeList znalezionej w module django.template.base. Mój kod wydaje się działać poprawnie, ale używam łatania małp do zastąpienia starej metody renderowania.

Czy istnieje bardziej elegancki sposób, w którym nie stosuje się łatek małpich? A może łatanie małp to najlepsza metoda?

Mój kod wygląda następująco:

''' 
This module monkey-patches Django template system to preserve 
indentation when rendering templates. 
''' 

import re 

from django.utils.encoding import force_text 
from django.utils.safestring import mark_safe 
from django.template.loader import render_to_string 
from django.template import Node, NodeList, TextNode 
from django.template.loader_tags import (BlockNode, ConstantIncludeNode, 
             IncludeNode) 


NEWLINES = re.compile(r'(\r\n|\r|\n)') 
INDENT = re.compile(r'(?:\r\n|\r|\n)([\ \t]+)') 


def get_indent(text, i=0): 
    ''' 
    Depending on value of `i`, returns first or last indent 
    (or any other if `i` is something other than 0 or -1) 
    found in `text`. Indent is any sequence of tabs or spaces 
    preceded by a newline. 
    ''' 
    try: 
     return INDENT.findall(text)[i] 
    except IndexError: 
     pass 


def reindent(self, context): 
    bits = '' 
    for node in self: 
     if isinstance(node, Node): 
      bit = self.render_node(node, context) 
     else: 
      bit = node 
     text = force_text(bit) 

     # Remove one indentation level 
     if isinstance(node, BlockNode): 
      if INDENT.match(text): 
       indent = get_indent(text) 
       text = re.sub(r'(\r\n|\r|\n)' + indent, r'\1', text) 

     # Add one indentation level 
     if isinstance(node, (BlockNode, ConstantIncludeNode, IncludeNode)): 
      text = text.strip() 
      if '\r' in text or '\n' in text: 
       indent = get_indent(bits, -1) 
       if indent: 
        text = NEWLINES.sub(r'\1' + indent, text) 

     bits += text 

    return mark_safe(bits) 


# Monkey-patching Django class 
NodeList.render = reindent 
+0

Jestem całkiem nowy w django, czy możesz podać przykład tego, jak mogę to zaimplementować w moim projekcie? –

Odpowiedz

1

Można użyć klasy dziedziczenia utworzyć inny NodeList ale będzie to prawdopodobnie wymagać pewnej łatanie na innym końcu. Twoje rozwiązanie wydaje się proste i proste.

class MyNodeList(NodeList): 
    def render(self, context): 
     # call super if you require so 
     # your reindent functionality 
3

Modyfikowanie warstwy szablonu byłoby ok, ale nie jest optymalny, ponieważ po prostu zajmuje jak węzeł jest renderowany, a nie cały dokument. Polecam writing custom middleware dla twojego projektu, aby wydrukować poprawnie renderowanie odpowiedzi dla stron HTML i CSS.

Twój middleware będą musiały wdrożyć process_template_response który powinien być używany do przeglądania i aktualizowania obiektu SimpleTemplateResponse:

  • Sprawdź atrybut is_rendered aby sprawdzić, czy odpowiedź została wygenerowana
  • Sprawdź typ dokumentu albo przez :
    • Patrząc żądanego typu (.html, .css) na końcu atrybutu template_name
    • Patrząc na atrybucie content_type (Django 1.5) lub ewentualnie mimetype dla starszych instaluje
  • re-format i zaktualizować świadczonych dokument wspaniały wygląd (Beautiful Soup jest wielki dla HTML, ale trzeba wybrać preferowany ładna drukarka lub rolka własne).

Myślę, że oprogramowanie pośredniczące jest o wiele bardziej eleganckim rozwiązaniem, ponieważ nie powoduje to żadnych leksykalnych zmian w plikach. Jest całkowicie oddzielony od logiki, która określa zawartość szablonu (gdzie nie ma żadnej firmy). Na koniec, chcesz, aby WSZYSTKIE twoje html i css wyglądały świetnie, więc po co w pierwszej kolejności wiązać to z szablonami?

Powiązane problemy