警惕Context的push()和pop()


警惕Context的push()和pop()

Published on Tue 09 Feb 2010 08:02 ( 1 month ago)
Django Python

遇到一个怪异的bug是在自己实现的一个可能存在嵌套的templatetags里,下面这行代码带入的templatecontext这个dict会被update到context_instance里面去,并且可能是同名的。

output = render_to_string(templatepath, templatecontext, context_instance)

看了django的文档其中Context上有 push()和pop(), 所以想当然地认为只要在调用前对context_instance 执行push(), 结束了pop()就可以保证templatecontext里的东西不会被混入context_instance里面去。

实际的情况却不是我所期待的,常常会出现context里的对象被替换了(由于是嵌套的,所以必然存在重名)。郁闷之下只好去看看push(), pop(),还有render_to_string()究竟在干什么。

原来这push(), pop()是这么实现的:

27         def push(self):
28             d = {}
29             self.dicts.append(d)
30             return d
31    
32         def pop(self):
33             if len(self.dicts) == 1:
34                 raise ContextPopException
35             return self.dicts.pop()

Render_to_string()是这样的:

157     def render_to_string(template_name,  dictionary=None, context_instance=None):
158         """
159         Loads the given template_name and renders it with the given dictionary as
160         context. The template_name may be a string to load a single template using
161         get_template, or it may be a tuple to use select_template to find one of
162         the templates in the list. Returns a string.
163         """
164         dictionary = dictionary or {}
165         if isinstance(template_name, (list, tuple)):
166             t = select_template(template_name)
167         else:
168             t = get_template(template_name)
169         if context_instance:
170             context_instance.update(dictionary)
171         else:
172             context_instance = Context(dictionary)
173         return t.render(context_instance)

这里用到的context.update()是这样实现的

75         def update(self, other_dict):
76             "Like dict.update(). Pushes an entire dictionary's keys and values onto the context."
77             if not hasattr(other_dict, '__getitem__'):
78                 raise TypeError('other_dict must be a mapping (dictionary-like) object.')
79             self.dicts.append(other_dict)
80             return other_dict

由此可见,我在调用Render_to_string()前push(), 后pop()根本不能达到我要的目的,事实上那个pop只是pop出update()进去的dictionary.

解决方案是,不需要push(), 每次render_to_string()后调用pop(), context_instance就复原了。


Related posts:


Search related in web:

Custom Search

RSS Feed

One click subscribe this blog in your google reader!

Be social!


Want to say something here? please sign in



Blog posts link to this page
What are friends tweeting?
Tags cloud
Monthly Archives