Django

Code

Ticket #4565: template-iter-render-r3369.patch

File template-iter-render-r3369.patch, 38.3 kB (added by Brian Harring <ferringb@gmail.com>, 1 year ago)
  • django/contrib/admin/templatetags/admin_modify.py

    old new  
    9494            return cls.nodelists[klass] 
    9595    get_nodelist = classmethod(get_nodelist) 
    9696 
    97     def render(self, context): 
     97    def iter_render(self, context): 
    9898        bound_field = template.resolve_variable(self.bound_field_var, context) 
    9999 
    100100        context.push() 
    101101        context['bound_field'] = bound_field 
    102102 
    103         output = self.get_nodelist(bound_field.field.__class__).render(context) 
     103        for chunk in self.get_nodelist(bound_field.field.__class__).iter_render(context): 
     104            yield chunk 
    104105        context.pop() 
    105         return output 
    106106 
    107107class FieldWrapper(object): 
    108108    def __init__(self, field ): 
     
    157157    def __init__(self, rel_var): 
    158158        self.rel_var = rel_var 
    159159 
    160     def render(self, context): 
     160    def iter_render(self, context): 
    161161        relation = template.resolve_variable(self.rel_var, context) 
    162162        context.push() 
    163163        if relation.field.rel.edit_inline == models.TABULAR: 
     
    169169        original = context.get('original', None) 
    170170        bound_related_object = relation.bind(context['form'], original, bound_related_object_class) 
    171171        context['bound_related_object'] = bound_related_object 
    172         t = loader.get_template(bound_related_object.template_name()) 
    173         output = t.render(context) 
     172        for chunk in loader.get_template(bound_related_object.template_name()).iter_render(context): 
     173            yield chunk 
    174174        context.pop() 
    175         return output 
    176175 
    177176def output_all(form_fields): 
    178177    return ''.join([str(f) for f in form_fields]) 
  • django/contrib/admin/templatetags/adminapplist.py

    old new  
    77    def __init__(self, varname): 
    88        self.varname = varname 
    99 
    10     def render(self, context): 
     10    def iter_render(self, context): 
    1111        from django.db import models 
    1212        from django.utils.text import capfirst 
    1313        app_list = [] 
     
    5454                        'models': model_list, 
    5555                    }) 
    5656        context[self.varname] = app_list 
    57         return '' 
     57        return () 
    5858 
    5959def get_admin_app_list(parser, token): 
    6060    """ 
  • django/contrib/admin/templatetags/log.py

    old new  
    1010    def __repr__(self): 
    1111        return "<GetAdminLog Node>" 
    1212 
    13     def render(self, context): 
     13    def iter_render(self, context): 
    1414        if self.user is None: 
    1515            context[self.varname] = LogEntry.objects.all().select_related()[:self.limit] 
    1616        else: 
    1717            if not self.user.isdigit(): 
    1818                self.user = context[self.user].id 
    1919            context[self.varname] = LogEntry.objects.filter(user__id__exact=self.user).select_related()[:self.limit] 
    20         return '' 
     20        return () 
    2121 
    2222class DoGetAdminLog: 
    2323    """ 
  • django/contrib/comments/templatetags/comments.py

    old new  
    2424        self.photo_options, self.rating_options = photo_options, rating_options 
    2525        self.is_public = is_public 
    2626 
    27     def render(self, context): 
     27    def iter_render(self, context): 
    2828        from django.conf import settings 
    2929        from django.utils.text import normalize_newlines 
    3030        import base64 
     
    3333            try: 
    3434                self.obj_id = template.resolve_variable(self.obj_id_lookup_var, context) 
    3535            except template.VariableDoesNotExist: 
    36                 return '' 
     36                return 
    3737            # Validate that this object ID is valid for this content-type. 
    3838            # We only have to do this validation if obj_id_lookup_var is provided, 
    3939            # because do_comment_form() validates hard-coded object IDs. 
     
    6767            context['hash'] = Comment.objects.get_security_hash(context['options'], context['photo_options'], context['rating_options'], context['target']) 
    6868            context['logout_url'] = settings.LOGOUT_URL 
    6969            default_form = loader.get_template(COMMENT_FORM) 
    70         output = default_form.render(context) 
     70        for chunk in default_form.iter_render(context): 
     71            yield chunk 
    7172        context.pop() 
    72         return output 
    7373 
    7474class CommentCountNode(template.Node): 
    7575    def __init__(self, package, module, context_var_name, obj_id, var_name, free): 
     
    7777        self.context_var_name, self.obj_id = context_var_name, obj_id 
    7878        self.var_name, self.free = var_name, free 
    7979 
    80     def render(self, context): 
     80    def iter_render(self, context): 
    8181        from django.conf import settings 
    8282        manager = self.free and FreeComment.objects or Comment.objects 
    8383        if self.context_var_name is not None: 
     
    8686            content_type__app_label__exact=self.package, 
    8787            content_type__model__exact=self.module, site__id__exact=settings.SITE_ID).count() 
    8888        context[self.var_name] = comment_count 
    89         return '' 
     89        return () 
    9090 
    9191class CommentListNode(template.Node): 
    9292    def __init__(self, package, module, context_var_name, obj_id, var_name, free, ordering, extra_kwargs=None): 
     
    9696        self.ordering = ordering 
    9797        self.extra_kwargs = extra_kwargs or {} 
    9898 
    99     def render(self, context): 
     99    def iter_render(self, context): 
    100100        from django.conf import settings 
    101101        get_list_function = self.free and FreeComment.objects.filter or Comment.objects.get_list_with_karma 
    102102        if self.context_var_name is not None: 
    103103            try: 
    104104                self.obj_id = template.resolve_variable(self.context_var_name, context) 
    105105            except template.VariableDoesNotExist: 
    106                 return '' 
     106                return () 
    107107        kwargs = { 
    108108            'object_id__exact': self.obj_id, 
    109109            'content_type__app_label__exact': self.package, 
     
    127127                comment_list = [c for c in comment_list if not c.is_hidden or (user_id == c.user_id)] 
    128128 
    129129        context[self.var_name] = comment_list 
    130         return '' 
     130        return () 
    131131 
    132132class DoCommentForm: 
    133133    """ 
  • django/core/servers/basehttp.py

    old new  
    309309        """ 
    310310        if not self.result_is_file() and not self.sendfile(): 
    311311            for data in self.result: 
    312                 self.write(data
     312                self.write(data, False
    313313            self.finish_content() 
    314314        self.close() 
    315315 
     
    377377        else: 
    378378            self._write('Status: %s\r\n' % self.status) 
    379379 
    380     def write(self, data): 
     380    def write(self, data, flush=True): 
    381381        """'write()' callable as specified by PEP 333""" 
    382382 
    383383        assert type(data) is StringType,"write() argument must be string" 
     
    394394 
    395395        # XXX check Content-Length and truncate if too many bytes written? 
    396396        self._write(data) 
    397         self._flush() 
     397        if flush: 
     398            self._flush() 
    398399 
    399400    def sendfile(self): 
    400401        """Platform-specific file transmission 
     
    421422        if not self.headers_sent: 
    422423            self.headers['Content-Length'] = "0" 
    423424            self.send_headers() 
    424         else: 
    425             pass # XXX check if content-length was too short? 
    426425 
    427426    def close(self): 
    428427        try: 
  • django/http/__init__.py

    old new  
    231231    content = property(_get_content, _set_content) 
    232232 
    233233    def __iter__(self): 
    234         self._iterator = self._container.__iter__() 
    235         return self 
    236  
    237     def next(self): 
    238         chunk = self._iterator.next() 
    239         if isinstance(chunk, unicode): 
    240             chunk = chunk.encode(self._charset) 
    241         return chunk 
     234        for chunk in self._container: 
     235            if isinstance(chunk, unicode): 
     236                chunk = chunk.encode(self._charset) 
     237            yield chunk 
    242238 
    243239    def close(self): 
    244240        if hasattr(self._container, 'close'): 
  • django/oldforms/__init__.py

    old new  
    309309        return data 
    310310    html2python = staticmethod(html2python) 
    311311 
     312    def iter_render(self, data): 
     313        # this even needed? 
     314        return (self.render(data),) 
     315 
    312316    def render(self, data): 
    313317        raise NotImplementedError 
    314318 
  • django/shortcuts/__init__.py

    old new  
    77from django.db.models.manager import Manager 
    88 
    99def render_to_response(*args, **kwargs): 
    10     return HttpResponse(loader.render_to_string(*args, **kwargs)) 
     10    return HttpResponse(loader.render_to_iter(*args, **kwargs)) 
    1111load_and_render = render_to_response # For backwards compatibility. 
    1212 
    1313def get_object_or_404(klass, *args, **kwargs): 
  • django/template/__init__.py

    old new  
    167167            for subnode in node: 
    168168                yield subnode 
    169169 
    170     def render(self, context): 
     170    def iter_render(self, context): 
    171171        "Display stage -- can be called many times" 
    172         return self.nodelist.render(context) 
     172        return self.nodelist.iter_render(context) 
     173     
     174    def render(self, context): 
     175        return ''.join(self.iter_render(context)) 
    173176 
    174177def compile_string(template_string, origin): 
    175178    "Compiles template_string into NodeList ready for rendering" 
     
    699702    return current 
    700703 
    701704class Node(object): 
     705    def iter_render(self, context): 
     706        return (self.render(context),) 
     707 
    702708    def render(self, context): 
    703709        "Return the node rendered as a string" 
    704         pass 
     710        return ''.join(self.iter_render(context)) 
    705711 
    706712    def __iter__(self): 
    707713        yield self 
     
    716722        return nodes 
    717723 
    718724class NodeList(list): 
     725 
    719726    def render(self, context): 
    720         bits = [] 
     727        return ''.join(self.iter_render(context)) 
     728 
     729    def iter_render(self, context): 
    721730        for node in self: 
    722             if isinstance(node, Node): 
    723                 bits.append(self.render_node(node, context)) 
    724             else: 
    725                 bits.append(node) 
    726         return ''.join(bits) 
     731            for chunk in node.iter_render(context): 
     732                yield chunk 
    727733 
    728734    def get_nodes_by_type(self, nodetype): 
    729735        "Return a list of all nodes of the given type" 
     
    732738            nodes.extend(node.get_nodes_by_type(nodetype)) 
    733739        return nodes 
    734740 
    735     def render_node(self, node, context): 
    736         return(node.render(context)) 
    737741 
    738742class DebugNodeList(NodeList): 
    739     def render_node(self, node, context): 
    740         try: 
    741             result = node.render(context) 
    742         except TemplateSyntaxError, e: 
    743             if not hasattr(e, 'source'): 
    744                 e.source = node.source 
    745             raise 
    746         except Exception, e: 
    747             from sys import exc_info 
    748             wrapped = TemplateSyntaxError('Caught an exception while rendering: %s' % e) 
    749             wrapped.source = node.source 
    750             wrapped.exc_info = exc_info() 
    751             raise wrapped 
    752         return result 
     743 
     744    def iter_render(self, node, context): 
     745        for node in self: 
     746            if not isinstance(node, Node): 
     747                yield node 
     748                continue 
     749            try: 
     750                for chunk in node.iter_render(context): 
     751                    yield chunk 
     752            except TemplateSyntaxError, e: 
     753                if not hasattr(e, 'source'): 
     754                    e.source = node.source 
     755                raise 
     756            except Exception, e: 
     757                from sys import exc_info 
     758                wrapped = TemplateSyntaxError('Caught an exception while rendering: %s' % e) 
     759                wrapped.source = node.source 
     760                wrapped.exc_info = exc_info() 
     761                raise wrapped 
    753762 
    754763class TextNode(Node): 
    755764    def __init__(self, s): 
     
    758767    def __repr__(self): 
    759768        return "<Text Node: '%s'>" % self.s[:25] 
    760769 
     770    def iter_render(self, context): 
     771        return (self.s,) 
     772 
    761773    def render(self, context): 
    762774        return self.s 
    763775 
     
    781793        else: 
    782794            return output 
    783795 
     796    def iter_render(self, context): 
     797        return (self.render(context),) 
     798 
    784799    def render(self, context): 
    785800        output = self.filter_expression.resolve(context) 
    786801        return self.encode_output(output) 
    787802 
    788803class DebugVariableNode(VariableNode): 
     804 
    789805    def render(self, context): 
    790806        try: 
    791807            output = self.filter_expression.resolve(context) 
     
    869885            def __init__(self, vars_to_resolve): 
    870886                self.vars_to_resolve = vars_to_resolve 
    871887 
     888            def iter_render(self, context): 
     889                return (self.render(context),) 
     890 
    872891            def render(self, context): 
    873892                resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve] 
    874893                return func(*resolved_vars) 
     
    891910                def __init__(self, vars_to_resolve): 
    892911                    self.vars_to_resolve = vars_to_resolve 
    893912 
    894                 def render(self, context): 
     913                def iter_render(self, context): 
    895914                    resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve] 
    896915                    if takes_context: 
    897916                        args = [context] + resolved_vars 
     
    907926                        else: 
    908927                            t = get_template(file_name) 
    909928                        self.nodelist = t.nodelist 
    910                     return self.nodelist.render(context_class(dict)) 
     929                    return self.nodelist.iter_render(context_class(dict)) 
    911930 
    912931            compile_func = curry(generic_tag_compiler, params, defaults, getattr(func, "_decorated_function", func).__name__, InclusionNode) 
    913932            compile_func.__doc__ = func.__doc__ 
  • django/template/defaulttags.py

    old new  
    1414        for index in xrange(len(data)-1, -1, -1): 
    1515            yield data[index] 
    1616 
    17  
    1817register = Library() 
    1918 
    2019class CommentNode(Node): 
    21     def render(self, context): 
    22         return '' 
     20    def iter_render(self, context): 
     21        return () 
    2322 
    2423class CycleNode(Node): 
    2524    def __init__(self, cyclevars, variable_name=None): 
     
    2827        self.counter = -1 
    2928        self.variable_name = variable_name 
    3029 
     30    def iter_render(self, context): 
     31        return (self.render(context),) 
     32 
    3133    def render(self, context): 
    3234        self.counter += 1 
    3335        value = self.cyclevars[self.counter % self.cyclevars_len] 
     
    3638        return value 
    3739 
    3840class DebugNode(Node): 
    39     def render(self, context): 
     41    def iter_render(self, context): 
    4042        from pprint import pformat 
    41         output = [pformat(val) for val in context] 
    42         output.append('\n\n'
    43         output.append(pformat(sys.modules)) 
    44         return ''.join(output
     43        for val in context: 
     44            yield pformat(val
     45        yield "\n\n" 
     46        yield pformat(sys.modules
    4547 
    4648class FilterNode(Node): 
    4749    def __init__(self, filter_expr, nodelist): 
    4850        self.filter_expr, self.nodelist = filter_expr, nodelist 
    4951 
    50     def render(self, context): 
     52    def iter_render(self, context): 
    5153        output = self.nodelist.render(context) 
    5254        # apply filters 
    5355        context.update({'var': output}) 
    5456        filtered = self.filter_expr.resolve(context) 
    5557        context.pop() 
    56         return filtered 
     58        return (filtered,) 
    5759 
    5860class FirstOfNode(Node): 
    5961    def __init__(self, vars): 
    6062        self.vars = vars 
    6163 
     64    def iter_render(self, context): 
     65        return (self.render(context),) 
     66 
    6267    def render(self, context): 
    6368        for var in self.vars: 
    6469            try: 
     
    9499        nodes.extend(self.nodelist_loop.get_nodes_by_type(nodetype)) 
    95100        return nodes 
    96101 
    97     def render(self, context): 
    98         nodelist = NodeList() 
     102    def iter_render(self, context): 
    99103        if 'forloop' in context: 
    100104            parentloop = context['forloop'] 
    101105        else: 
     
    103107        context.push() 
    104108        try: 
    105109            values = self.sequence.resolve(context, True) 
     110            if values is None: 
     111                values = () 
     112            elif not hasattr(values, '__len__'): 
     113                values = list(values) 
    106114        except VariableDoesNotExist: 
    107             values = [] 
    108         if values is None: 
    109             values = [] 
    110         if not hasattr(values, '__len__'): 
    111             values = list(values) 
     115            values = () 
    112116        len_values = len(values) 
    113117        if self.reversed: 
    114118            values = reversed(values) 
     
    131135                context.update(dict(zip(self.loopvars, item))) 
    132136            else: 
    133137                context[self.loopvars[0]] = item 
     138            # we inline this to avoid the overhead since fornode is pretty common. 
    134139            for node in self.nodelist_loop: 
    135                 nodelist.append(node.render(context)) 
     140                for chunk in node.iter_render(context): 
     141                    yield chunk 
    136142            if unpack: 
    137143                # The loop variables were pushed on to the context so pop them 
    138144                # off again. This is necessary because the tag lets the length 
     
    141147                # context. 
    142148                context.pop() 
    143149        context.pop() 
    144         return nodelist.render(context) 
    145150 
    146151class IfChangedNode(Node): 
    147152    def __init__(self, nodelist, *varlist): 
     
    149154        self._last_seen = None 
    150155        self._varlist = varlist 
    151156 
    152     def render(self, context): 
     157    def iter_render(self, context): 
    153158        if 'forloop' in context and context['forloop']['first']: 
    154159            self._last_seen = None 
    155160        try: 
     
    167172            self._last_seen = compare_to 
    168173            context.push() 
    169174            context['ifchanged'] = {'firstloop': firstloop} 
    170             content = self.nodelist.render(context) 
     175            for chunk in self.nodelist.iter_render(context): 
     176                yield chunk 
    171177            context.pop() 
    172             return content 
    173         else: 
    174             return '' 
    175178 
    176179class IfEqualNode(Node): 
    177180    def __init__(self, var1, var2, nodelist_true, nodelist_false, negate): 
     
    182185    def __repr__(self): 
    183186        return "<IfEqualNode>" 
    184187 
    185     def render(self, context): 
     188    def iter_render(self, context): 
    186189        try: 
    187190            val1 = resolve_variable(self.var1, context) 
    188191        except VariableDoesNotExist: 
     
    192195        except VariableDoesNotExist: 
    193196            val2 = None 
    194197        if (self.negate and val1 != val2) or (not self.negate and val1 == val2): 
    195             return self.nodelist_true.render(context) 
    196         return self.nodelist_false.render(context) 
     198            return self.nodelist_true.iter_render(context) 
     199        return self.nodelist_false.iter_render(context) 
    197200 
    198201class IfNode(Node): 
    199202    def __init__(self, bool_exprs, nodelist_true, nodelist_false, link_type): 
     
    218221        nodes.extend(self.nodelist_false.get_nodes_by_type(nodetype)) 
    219222        return nodes 
    220223 
    221     def render(self, context): 
     224    def iter_render(self, context): 
    222225        if self.link_type == IfNode.LinkTypes.or_: 
    223226            for ifnot, bool_expr in self.bool_exprs: 
    224227                try: 
     
    226229                except VariableDoesNotExist: 
    227230                    value = None 
    228231                if (value and not ifnot) or (ifnot and not value): 
    229                     return self.nodelist_true.render(context) 
    230             return self.nodelist_false.render(context) 
     232                    return self.nodelist_true.iter_render(context) 
     233            return self.nodelist_false.iter_render(context) 
    231234        else: 
    232235            for ifnot, bool_expr in self.bool_exprs: 
    233236                try: 
     
    235238                except VariableDoesNotExist: 
    236239                    value = None 
    237240                if not ((value and not ifnot) or (ifnot and not value)): 
    238                     return self.nodelist_false.render(context) 
    239             return self.nodelist_true.render(context) 
     241                    return self.nodelist_false.iter_render(context) 
     242            return self.nodelist_true.iter_render(context) 
    240243 
    241244    class LinkTypes: 
    242245        and_ = 0, 
     
    247250        self.target, self.expression = target, expression 
    248251        self.var_name = var_name 
    249252 
    250     def render(self, context): 
     253    def iter_render(self, context): 
    251254        obj_list = self.target.resolve(context, True) 
    252255        if obj_list == None: # target_var wasn't found in context; fail silently 
    253256            context[self.var_name] = [] 
    254             return '' 
     257            return () 
    255258        output = [] # list of dictionaries in the format {'grouper': 'key', 'list': [list of contents]} 
    256259        for obj in obj_list: 
    257260            grouper = self.expression.resolve(obj, True) 
     
    261264            else: 
    262265                output.append({'grouper': grouper, 'list': [obj]}) 
    263266        context[self.var_name] = output 
    264         return '' 
     267        return () 
    265268 
    266269def include_is_allowed(filepath): 
    267270    for root in settings.ALLOWED_INCLUDE_ROOTS: 
     
    273276    def __init__(self, filepath, parsed): 
    274277        self.filepath, self.parsed = filepath, parsed 
    275278 
    276     def render(self, context): 
     279    def iter_render(self, context): 
    277280        if not include_is_allowed(self.filepath): 
    278281            if settings.DEBUG: 
    279                 return "[Didn't have permission to include file]" 
     282                return ("[Didn't have permission to include file]",) 
    280283            else: 
    281284                return '' # Fail silently for invalid includes. 
    282285        try: 
     
    287290            output = '' 
    288291        if self.parsed: 
    289292            try: 
    290                 t = Template(output, name=self.filepath) 
    291                 return t.render(context) 
     293                return Template(output, name=self.filepath).iter_render(context) 
    292294            except TemplateSyntaxError, e: 
    293295                if settings.DEBUG: 
    294296                    return "[Included template had syntax error: %s]" % e 
    295297                else: 
    296298                    return '' # Fail silently for invalid included templates. 
    297         return output 
     299        return (output,) 
    298300 
    299301class LoadNode(Node): 
    300     def render(self, context): 
    301         return '' 
     302    def iter_render(self, context): 
     303        return () 
    302304 
    303305class NowNode(Node): 
    304306    def __init__(self, format_string): 
    305307        self.format_string = format_string 
    306308 
     309    def iter_render(self, context): 
     310        return (self.render(context),) 
     311 
    307312    def render(self, context): 
    308313        from datetime import datetime 
    309314        from django.utils.dateformat import DateFormat 
     
    332337    def __init__(self, tagtype): 
    333338        self.tagtype = tagtype 
    334339 
     340    def iter_render(self, context): 
     341        return (self.render(context),) 
     342 
    335343    def render(self, context): 
    336344        return self.mapping.get(self.tagtype, '') 
    337345 
     
    341349        self.args = args 
    342350        self.kwargs = kwargs 
    343351 
    344     def render(self, context): 
     352    def iter_render(self, context): 
    345353        from django.core.urlresolvers import reverse, NoReverseMatch 
    346354        args = [arg.resolve(context) for arg in self.args] 
    347355        kwargs = dict([(k, v.resolve(context)) for k, v in self.kwargs.items()]) 
    348356        try: 
    349             return reverse(self.view_name, args=args, kwargs=kwargs
     357            return (reverse(self.view_name, args=args, kwargs=kwargs),
    350358        except NoReverseMatch: 
    351359            try: 
    352360                project_name = settings.SETTINGS_MODULE.split('.')[0] 
    353361                return reverse(project_name + '.' + self.view_name, args=args, kwargs=kwargs) 
    354362            except NoReverseMatch: 
    355                 return '' 
     363                return () 
    356364 
    357365class WidthRatioNode(Node): 
    358366    def __init__(self, val_expr, max_expr, max_width): 
     
    360368        self.max_expr = max_expr 
    361369        self.max_width = max_width 
    362370 
     371    def iter_render(self, context): 
     372        return (self.render(context),) 
     373 
    363374    def render(self, context): 
    364375        try: 
    365376            value = self.val_expr.resolve(context) 
     
    383394    def __repr__(self): 
    384395        return "<WithNode>" 
    385396 
    386     def render(self, context): 
     397    def iter_render(self, context): 
    387398        val = self.var.resolve(context) 
    388399        context.push() 
    389400        context[self.name] = val 
    390         output = self.nodelist.render(context) 
     401        for chunk in self.nodelist.iter_render(context): 
     402            yield chunk 
    391403        context.pop() 
    392         return output 
    393404 
    394405#@register.tag 
    395406def comment(parser, token): 
  • django/template/loader.py

    old new  
    8787    """ 
    8888    return Template(source, origin, name) 
    8989 
    90 def render_to_string(template_name, dictionary=None, context_instance=None): 
    91     """ 
    92     Loads the given template_name and renders it with the given dictionary as 
    93     context. The template_name may be a string to load a single template using 
    94     get_template, or it may be a tuple to use select_template to find one of 
    95     the templates in the list. Returns a string. 
    96     """ 
    97     dictionary = dictionary or {} 
     90def _render_setup(template_name, dictionary=None, context_instance=None): 
     91    """ 
     92    common setup code for render_to_string and render_to_iter 
     93    """ 
     94    if dictionary is None: 
     95        dictionary = {} 
    9896    if isinstance(template_name, (list, tuple)): 
    9997        t = select_template(template_name) 
    10098    else: 
     
    103101        context_instance.update(dictionary) 
    104102    else: 
    105103        context_instance = Context(dictionary) 
    106     return t.render(context_instance) 
     104    return t, context_instance 
     105 
     106def render_to_string(template_name, dictionary=None, context_instance=None): 
     107    """ 
     108    Loads the given template_name and renders it with the given dictionary as 
     109    context. The template_name may be a string to load a single template using 
     110    get_template, or it may be a tuple to use select_template to find one of 
     111    the templates in the list. Returns a string. 
     112    """ 
     113    t, c = _render_setup(template_name, dictionary=dictionary, context_instance=context_instance) 
     114    return t.render(c) 
     115 
     116def render_to_iter(template_name, dictionary=None, context_instance=None): 
     117    """ 
     118    Loads the given template_name and renders it with the given dictionary as 
     119    context. The template_name may be a string to load a single template using 
     120    get_template, or it may be a tuple to use select_template to find one of 
     121    the templates in the list. Returns a string. 
     122    """ 
     123    t, c = _render_setup(template_name, dictionary=dictionary, context_instance=context_instance) 
     124    return t.iter_render(c) 
     125 
    107126 
    108127def select_template(template_name_list): 
    109128    "Given a list of template names, returns the first that can be loaded." 
  • django/template/loader_tags.py

    old new  
    1515    def __repr__(self): 
    1616        return "<Block Node: %s. Contents: %r>" % (self.name, self.nodelist) 
    1717 
    18     def render(self, context): 
     18    def iter_render(self, context): 
    1919        context.push() 
    2020        # Save context in case of block.super(). 
    2121        self.context = context 
    2222        context['block'] = self 
    23         result = self.nodelist.render(context) 
     23        for chunk in self.nodelist.iter_render(context): 
     24            yield chunk 
    2425        context.pop() 
    25         return result 
    2626 
    2727    def super(self): 
    2828        if self.parent: 
     
    5959        else: 
    6060            return get_template_from_string(source, origin, parent) 
    6161 
    62     def render(self, context): 
     62    def iter_render(self, context): 
    6363        compiled_parent = self.get_parent(context) 
    6464        parent_is_child = isinstance(compiled_parent.nodelist[0], ExtendsNode) 
    6565        parent_blocks = dict([(n.name, n) for n in compiled_parent.nodelist.get_nodes_by_type(BlockNode)]) 
     
    7979                parent_block.parent = block_node.parent 
    8080                parent_block.add_parent(parent_block.nodelist) 
    8181                parent_block.nodelist = block_node.nodelist 
    82         return compiled_parent.render(context) 
     82        return compiled_parent.iter_render(context) 
    8383 
    8484class ConstantIncludeNode(Node): 
    8585    def __init__(self, template_path): 
     
    9191                raise 
    9292            self.template = None 
    9393 
    94     def render(self, context): 
     94    def iter_render(self, context): 
    9595        if self.template: 
    96             return self.template.render(context) 
    97         else: 
    98             return '' 
     96            return self.template.iter_render(context) 
     97        return () 
    9998 
    10099class IncludeNode(Node): 
    101100    def __init__(self, template_name): 
    102101        self.template_name = template_name 
    103102 
    104     def render(self, context): 
     103    def iter_render(self, context): 
    105104        try: 
    106105            template_name = resolve_variable(self.template_name, context) 
    107106            t = get_template(template_name) 
    108             return t.render(context) 
     107            return t.iter_render(context) 
    109108        except TemplateSyntaxError, e: 
    110109            if settings.TEMPLATE_DEBUG: 
    111110                raise 
    112             return '' 
     111            return () 
    113112        except: 
    114             return '' # Fail silently for invalid included templates. 
     113            return () # Fail silently for invalid included templates. 
    115114 
    116115def do_block(parser, token): 
    117116    """ 
  • django/test/utils.py

    old new  
    1717    """ 
    1818    dispatcher.send(signal=signals.template_rendered, sender=self, template=self, context=context) 
    1919    return self.nodelist.render(context) 
     20 
     21def instrumented_test_iter_render(self, context): 
     22    """An instrumented Template iter_render method, providing a signal  
     23    that can be intercepted by the test system Client 
     24     
     25    """ 
     26    for chunk in self.nodelist.iter_render(context): 
     27        yield chunk 
     28    dispatcher.send(signal=signals.template_rendered, sender=self, template=self, context=context) 
    2029     
    2130class TestSMTPConnection(object): 
    2231    """A substitute SMTP connection for use during test sessions. 
     
    4453         
    4554    """ 
    4655    Template.original_render = Template.render 
     56    Template.original_iter_render = Template.iter_render 
    4757    Template.render = instrumented_test_render 
     58    Template.iter_render = instrumented_test_render 
    4859     
    4960    mail.original_SMTPConnection = mail.SMTPConnection 
    5061    mail.SMTPConnection = TestSMTPConnection 
     
    5970         
    6071    """ 
    6172    Template.render = Template.original_render 
    62     del Template.original_render 
     73    Template.iter_render = Template.original_iter_render 
     74    del Template.original_render, Template.original_iter_render 
    6375     
    6476    mail.SMTPConnection = mail.original_SMTPConnection 
    6577    del mail.original_SMTPConnection 
  • django/views/debug.py

    old new  
    137137        'template_does_not_exist': template_does_not_exist, 
    138138        'loader_debug_info': loader_debug_info, 
    139139    }) 
    140     return HttpResponseServerError(t.render(c), mimetype='text/html') 
     140    return HttpResponseServerError(t.iter_render(c), mimetype='text/html') 
    141141 
    142142def technical_404_response(request, exception): 
    143143    "Create a technical 404 error response. The exception should be the Http404." 
     
    160160        'request_protocol': request.is_secure() and "https" or "http", 
    161161        'settings': get_safe_settings(), 
    162162    }) 
    163     return HttpResponseNotFound(t.render(c), mimetype='text/html') 
     163    return HttpResponseNotFound(t.iter_render(c), mimetype='text/html') 
    164164 
    165165def empty_urlconf(request): 
    166166    "Create an empty URLconf 404 error response." 
     
    168168    c = Context({ 
    169169        'project_name': settings.SETTINGS_MODULE.split('.')[0] 
    170170    }) 
    171     return HttpResponseNotFound(t.render(c), mimetype='text/html') 
     171    return HttpResponseNotFound(t.iter_render(c), mimetype='text/html') 
    172172 
    173173def _get_lines_from_file(filename, lineno, context_lines, loader=None, module_name=None): 
    174174    """ 
  • django/views/defaults.py

    old new  
    7676            The path of the requested URL (e.g., '/app/pages/bad_page/') 
    7777    """ 
    7878    t = loader.get_template(template_name) # You need to create a 404.html template. 
    79     return http.HttpResponseNotFound(t.render(RequestContext(request, {'request_path': request.path}))) 
     79    return http.HttpResponseNotFound(t.iter_render(RequestContext(request, {'request_path': request.path}))) 
    8080 
    8181def server_error(request, template_name='500.html'): 
    8282    """ 
     
    8686    Context: None 
    8787    """ 
    8888    t = loader.get_template(template_name) # You need to create a 500.html template. 
    89     return http.HttpResponseServerError(t.render(Context({}))) 
     89    return http.HttpResponseServerError(t.iter_render(Context({}))) 
  • django/views/generic/create_update.py

    old new  
    6868            c[key] = value() 
    6969        else: 
    7070            c[key] = value 
    71     return HttpResponse(t.render(c)) 
     71    return HttpResponse(t.iter_render(c)) 
    7272 
    7373def update_object(request, model, object_id=None, slug=None, 
    7474        slug_field=None, template_name=None, template_loader=loader, 
     
    141141            c[key] = value() 
    142142        else: 
    143143            c[key] = value 
    144     response = HttpResponse(t.render(c)) 
     144    response = HttpResponse(t.iter_render(c)) 
    145145    populate_xheaders(request, response, model, getattr(object, object._meta.pk.attname)) 
    146146    return response 
    147147 
     
    195195                c[key] = value() 
    196196            else: 
    197197                c[key] = value 
    198         response = HttpResponse(t.render(c)) 
     198        response = HttpResponse(t.iter_render(c)) 
    199199        populate_xheaders(request, response, model, getattr(object, object._meta.pk.attname)) 
    200200        return response 
  • django/views/generic/date_based.py

    old new