`
marlonyao
  • 浏览: 248921 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

再一个用于调试Django模板的标签

阅读更多
主要用于在Html中递归输出对象的属性,这对调试Django相当有用。

用法:
{% inspect object %}



实现:
from django import template
import re
register = template.Library()

def do_inspect(parser, token):
    try:
        tag_name, var_name = token.split_contents()
    except ValueException:
        msg = '%r tag requires a single parameter' % token.split_contents()[0]
        raise template.TemplateSyntaxError(msg)
    return DumpVarNode(var_name)

import types
method_types = (types.BuiltinFunctionType, types.BuiltinMethodType, types.MethodType, types.FunctionType,)

from django.utils.html import escape
class DumpVarNode(template.Node):
    def __init__(self, var_name):
        self.var_name = var_name
        self.var = template.Variable(var_name)
        self._objects = []     # contains travased objects

    def render(self, context):
        var_value = self.var.resolve(context)
        html = '''
<script>
    if (!window.jQuery) {
        document.write('<scrip' + 't src="http://code.jquery.com/jquery-1.4.2.js" type="text/javascript"></sc' + 'ript>');
    }
</script>
<script>
(function($) {
    $(function() {
        $('.djt_var_head').click(function() {
            $('.djt_display_area textarea').val($(this).find('.djt_var_detailed').text())
        });
        $('.djt_exp').click(function() {
            $(this).closest('.djt_var_head').find('+ .djt_var_body').toggle();
            var expcol = $(this).toggleClass('djx_expanded');
            if (expcol.hasClass('djx_expanded')) {
                expcol.html('-');
            } else if (varBody.length > 0) {
                expcol.html('+');
            }
        })
    });
})(jQuery);
</script>
<style type="text/css">
    .djt_render {
        font-family: monospace;
        color: #333;
        line-height: 150%;
    }
    .djt_var_name {
        color: #000;
    }
    .djt_var_value {
        color: #666;
    }
    .djt_var_body {
        padding-left: 2em;
    }
    .djt_type_type {
        color: #00681C;
        font-weight: bold;
    }
    .djt_type_str, .djt_type_int, .djt_type_long, .djt_type_float, .djt_type_bool {
        color: #3333CC;
        font-weight: bold;
    }
    .djt_type_instance {
        color: #256;
        font-weight: bold;
    }
    .djt_var_id {
        /*color: blue;*/
    }
</style>'''
        html += '<div class="djt_render">'
        html += self._render_var(self.var_name, var_value, expand_props=True)
        html += '<div class="djt_display_area"><textarea rows="10" cols="80"></textarea></div>'
        html += '</div>'
        return html

    def _render_var(self, var_name, var_value, expand_props=False):
        already_exists = any([var_value is x for x in self._objects])
        self._objects.append(var_value)

        props = self.get_var_props(var_value)
        html = '<div class="djt_var">\n'
        html += self._render_var_head(var_name, var_value, props, expand_props, exists=already_exists)
        html += self._render_var_body(var_value, props, expand_props, exists=already_exists)
        html += '</div>'
        return html

    def _render_var_head(self, var_name, var_value, props, expand_props = False, exists=False):
        html = '<div class="djt_var_head">'
        if not exists:
            html += '<a name="djt_%s"></a>' % id(var_value)
        expanded = len(props) == 0 or exists or expand_props
        html += '''\
                    <span class="djt_exp %s">%s</span>
                    <span class="djt_var_name">%s:</span>
                    <span class="djt_var_value djt_type_%s">%s</span>
                    %s
                    <div class="djt_var_detailed" style="display:none">%s</div>
                </div>''' % (
            'djx_expanded' if expanded else '',
            '-' if expanded else '+',
            escape(var_name),
            self._value_type(var_value),
            self._str_value(var_value),
            self._render_return_link(var_value) if exists else '',
            self._detailed_str(var_value),
        )
        return html

    def _render_return_link(self, var):
        return '<a class="djt_jumplink" href="#djt_%s">here<a/>' % id(var)

    def _render_var_body(self, var_value, props, expand_props = False, exists=False):
        if len(props) == 0 or exists: return ''

        html = '<div class="djt_var_body" %s>' % ('' if expand_props else 'style="display:none"')
        for prop_name, prop_value in props:
            html  += self._render_var(prop_name, prop_value)
        html += '</div>'
        return html

    def _value_type(self, var):
        if var is None:
            return 'none'
        if type(var) in (bool, int, long, float, str, type):
            return type(var).__name__
        if type(var) in (unicode,):
            return 'str'
        return 'instance'
    
    def _detailed_str(self, var):
        tmp = '''\
type: %s
bases: %s
id: %s
str: "%s"
repr: %r
''' % (
    type(var).__name__, type(var).__bases__, id(var),
    var, var, 
)
        return escape(tmp)

    def get_var_props(self, var_value):
        if isinstance(var_value, (int, long, bool, float, str, unicode)):
            return []
        if isinstance(var_value, method_types):
            return []

        props = []
        for prop in dir(var_value):
            if prop.startswith('_'):
                continue
            try:
                prop_value = getattr(var_value, prop)
                # ingore builtin type
                if isinstance(prop_value, method_types):
                    continue

                props.append( (prop, prop_value) )
            except Exception, e:
                props.append( (prop, e) )  # TODO: indicator as error

        return props
    def _str_value(self, val):
        if isinstance(val, (bool, int, long, str, float)):
            strval = repr(val)
        elif isinstance(val, unicode):
            strval = repr(val)[1:]
        elif isinstance(val, (list, tuple, dict)):
            strval = str(val)
        else:
            try:
                strval = val.__class__.__name__
            except:
                strval = 'error occured'
        return escape(str(strval))

register.tag('inspect', do_inspect)

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics