2013-08-19 71 views
5

Tôi muốn tạo mã HTML và CSS có thể đọc được (được thụt lề chính xác) được xử lý trước bởi hệ thống mẫu Django cho ứng dụng độc lập của tôi.thụt lề thích hợp trong các mẫu Django (không có bản vá lỗi khỉ)?

Tôi đã sửa đổi phương thức hiển thị từ lớp NodeList được tìm thấy trong mô-đun django.template.base. Mã của tôi có vẻ hoạt động đúng cách, nhưng tôi đang sử dụng khỉ vá để thay thế phương thức hiển thị cũ.

Có cách nào thanh lịch hơn không sử dụng tính năng vá khỉ trong trường hợp này không? Hoặc có lẽ khỉ vá là cách tốt nhất ở đây?

Mã của tôi trông như thế này:

''' 
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

Tôi khá mới với django, bạn có thể cung cấp ví dụ về cách tôi có thể triển khai điều này trong dự án của mình không? –

Trả lời

1

Bạn có thể sử dụng lớp thừa kế để tạo ra một khác nhau NodeList nhưng nó có thể sẽ yêu cầu một số vá trên một kết thúc khác nhau. Giải pháp của bạn có vẻ đơn giản và đơn giản.

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

Sửa đổi lớp mẫu sẽ ổn, nhưng không tối ưu, vì nó chỉ xử lý cách nút được hiển thị chứ không phải toàn bộ tài liệu. Tôi sẽ giới thiệu writing custom middleware cho dự án của bạn để in đẹp phản hồi được hiển thị cho các trang html và css.

middleware của bạn sẽ cần phải thực hiện process_template_response mà nên được sử dụng để xem và cập nhật các đối tượng SimpleTemplateResponse:

  • Kiểm tra thuộc tính is_rendered để xem câu trả lời đã được trả lại
  • Xác minh loại tài liệu bằng một trong hai :
    • Tìm loại tệp mong muốn (.html, .css) ở cuối của template_name thuộc tính
    • .210
    • Nhìn vào thuộc tính content_type (Django 1.5) hoặc có thể mimetype cho tuổi cài đặt
  • Tái định dạng và cập nhật tài liệu render của bạn trông tuyệt đẹp (Beautiful Soup là rất tốt cho HTML, nhưng bạn sẽ cần phải chọn preffered của bạn khá máy in hoặc cuộn của riêng bạn).

Tôi nghĩ Middleware là giải pháp thanh lịch hơn vì điều này cuối cùng không làm thay đổi từ vựng đối với tệp của bạn. Nó hoàn toàn tách biệt với logic xác định nội dung mẫu của bạn (nơi mà nó không có doanh nghiệp). Cuối cùng, bạn muốn TẤT CẢ html và css của bạn trông tuyệt vời, vậy tại sao lại buộc nó vào mẫu của bạn ngay từ đầu?

Các vấn đề liên quan