We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Make StreamField lazily fetch related objects
I have a site that includes a list of pages in the footer (privacy policy, terms and conditions, etc). This is implemented using a `wagtailsettings` model with a join table/InlinePanel to `wagtailcore.Page`. Every page load thus fetches these pages to print their URL and title in the footer.

It appears that when a page is fetched, any related models referenced in that pages StreamField contents are also fetched. This means that loading the links for the footer of one page means fetching all of the images contained in the content of all of the footer pages. These extra database calls are clearly wasteful.

StreamField instances should lazily fetch related objects when the StreamField is first accessed, instead of as soon as it is loaded.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `wagtail/wagtailcore/blocks/stream_block.py`
Content:
```
1 from __future__ import absolute_import, unicode_literals
2 
3 import collections
4 
5 from django import forms
6 from django.core.exceptions import ValidationError
7 from django.forms.utils import ErrorList
8 from django.template.loader import render_to_string
9 from django.utils.encoding import python_2_unicode_compatible, force_text
10 from django.utils.html import format_html_join
11 from django.utils.safestring import mark_safe
12 
13 import six
14 
15 from wagtail.wagtailcore.utils import escape_script
16 
17 from .base import Block, DeclarativeSubBlocksMetaclass, BoundBlock
18 from .utils import indent, js_dict
19 
20 
21 __all__ = ['BaseStreamBlock', 'StreamBlock', 'StreamValue']
22 
23 
24 class BaseStreamBlock(Block):
25     # TODO: decide what it means to pass a 'default' arg to StreamBlock's constructor. Logically we want it to be
26     # of type StreamValue, but we can't construct one of those because it needs a reference back to the StreamBlock
27     # that we haven't constructed yet...
28     class Meta:
29         @property
30         def default(self):
31             return StreamValue(self, [])
32 
33     def __init__(self, local_blocks=None, **kwargs):
34         self._constructor_kwargs = kwargs
35 
36         super(BaseStreamBlock, self).__init__(**kwargs)
37 
38         self.child_blocks = self.base_blocks.copy()  # create a local (shallow) copy of base_blocks so that it can be supplemented by local_blocks
39         if local_blocks:
40             for name, block in local_blocks:
41                 block.set_name(name)
42                 self.child_blocks[name] = block
43 
44         self.dependencies = self.child_blocks.values()
45 
46     def render_list_member(self, block_type_name, value, prefix, index, errors=None):
47         """
48         Render the HTML for a single list item. This consists of an <li> wrapper, hidden fields
49         to manage ID/deleted state/type, delete/reorder buttons, and the child block's own HTML.
50         """
51         child_block = self.child_blocks[block_type_name]
52         child = child_block.bind(value, prefix="%s-value" % prefix, errors=errors)
53         return render_to_string('wagtailadmin/block_forms/stream_member.html', {
54             'child_blocks': self.child_blocks.values(),
55             'block_type_name': block_type_name,
56             'prefix': prefix,
57             'child': child,
58             'index': index,
59         })
60 
61     def html_declarations(self):
62         return format_html_join(
63             '\n', '<script type="text/template" id="{0}-newmember-{1}">{2}</script>',
64             [
65                 (
66                     self.definition_prefix,
67                     name,
68                     mark_safe(escape_script(self.render_list_member(name, child_block.meta.default, '__PREFIX__', '')))
69                 )
70                 for name, child_block in self.child_blocks.items()
71             ]
72         )
73 
74     @property
75     def media(self):
76         return forms.Media(js=['wagtailadmin/js/blocks/sequence.js', 'wagtailadmin/js/blocks/stream.js'])
77 
78     def js_initializer(self):
79         # compile a list of info dictionaries, one for each available block type
80         child_blocks = []
81         for name, child_block in self.child_blocks.items():
82             # each info dictionary specifies at least a block name
83             child_block_info = {'name': "'%s'" % name}
84 
85             # if the child defines a JS initializer function, include that in the info dict
86             # along with the param that needs to be passed to it for initializing an empty/default block
87             # of that type
88             child_js_initializer = child_block.js_initializer()
89             if child_js_initializer:
90                 child_block_info['initializer'] = child_js_initializer
91 
92             child_blocks.append(indent(js_dict(child_block_info)))
93 
94         opts = {
95             'definitionPrefix': "'%s'" % self.definition_prefix,
96             'childBlocks': '[\n%s\n]' % ',\n'.join(child_blocks),
97         }
98 
99         return "StreamBlock(%s)" % js_dict(opts)
100 
101     def render_form(self, value, prefix='', errors=None):
102         if errors:
103             if len(errors) > 1:
104                 # We rely on ListBlock.clean throwing a single ValidationError with a specially crafted
105                 # 'params' attribute that we can pull apart and distribute to the child blocks
106                 raise TypeError('ListBlock.render_form unexpectedly received multiple errors')
107             error_list = errors.as_data()[0].params
108         else:
109             error_list = None
110 
111         # drop any child values that are an unrecognised block type
112         valid_children = [child for child in value if child.block_type in self.child_blocks]
113 
114         list_members_html = [
115             self.render_list_member(child.block_type, child.value, "%s-%d" % (prefix, i), i,
116                 errors=error_list[i] if error_list else None)
117             for (i, child) in enumerate(valid_children)
118         ]
119 
120         return render_to_string('wagtailadmin/block_forms/stream.html', {
121             'label': self.label,
122             'prefix': prefix,
123             'list_members_html': list_members_html,
124             'child_blocks': self.child_blocks.values(),
125             'header_menu_prefix': '%s-before' % prefix,
126         })
127 
128     def value_from_datadict(self, data, files, prefix):
129         count = int(data['%s-count' % prefix])
130         values_with_indexes = []
131         for i in range(0, count):
132             if data['%s-%d-deleted' % (prefix, i)]:
133                 continue
134             block_type_name = data['%s-%d-type' % (prefix, i)]
135             try:
136                 child_block = self.child_blocks[block_type_name]
137             except KeyError:
138                 continue
139 
140             values_with_indexes.append(
141                 (
142                     int(data['%s-%d-order' % (prefix, i)]),
143                     block_type_name,
144                     child_block.value_from_datadict(data, files, '%s-%d-value' % (prefix, i)),
145                 )
146             )
147 
148         values_with_indexes.sort()
149         return StreamValue(self, [
150             (child_block_type_name, value)
151             for (index, child_block_type_name, value) in values_with_indexes
152         ])
153 
154     def clean(self, value):
155         cleaned_data = []
156         errors = []
157         for child in value:  # child is a BoundBlock instance
158             try:
159                 cleaned_data.append(
160                     (child.block.name, child.block.clean(child.value))
161                 )
162             except ValidationError as e:
163                 errors.append(ErrorList([e]))
164             else:
165                 errors.append(None)
166 
167         if any(errors):
168             # The message here is arbitrary - outputting error messages is delegated to the child blocks,
169             # which only involves the 'params' list
170             raise ValidationError('Validation error in StreamBlock', params=errors)
171 
172         return StreamValue(self, cleaned_data)
173 
174     def to_python(self, value):
175         # the incoming JSONish representation is a list of dicts, each with a 'type' and 'value' field.
176         # Convert this to a StreamValue backed by a list of (type, value) tuples
177         return StreamValue(self, [
178             (child_data['type'], self.child_blocks[child_data['type']].to_python(child_data['value']))
179             for child_data in value
180             if child_data['type'] in self.child_blocks
181         ])
182 
183     def get_prep_value(self, value):
184         if value is None:
185             # treat None as identical to an empty stream
186             return []
187 
188         return [
189             {'type': child.block.name, 'value': child.block.get_prep_value(child.value)}
190             for child in value  # child is a BoundBlock instance
191         ]
192 
193     def render_basic(self, value):
194         return format_html_join('\n', '<div class="block-{1}">{0}</div>',
195             [(force_text(child), child.block_type) for child in value]
196         )
197 
198     def get_searchable_content(self, value):
199         content = []
200 
201         for child in value:
202             content.extend(child.block.get_searchable_content(child.value))
203 
204         return content
205 
206     def deconstruct(self):
207         """
208         Always deconstruct StreamBlock instances as if they were plain StreamBlocks with all of the
209         field definitions passed to the constructor - even if in reality this is a subclass of StreamBlock
210         with the fields defined declaratively, or some combination of the two.
211 
212         This ensures that the field definitions get frozen into migrations, rather than leaving a reference
213         to a custom subclass in the user's models.py that may or may not stick around.
214         """
215         path = 'wagtail.wagtailcore.blocks.StreamBlock'
216         args = [self.child_blocks.items()]
217         kwargs = self._constructor_kwargs
218         return (path, args, kwargs)
219 
220 
221 class StreamBlock(six.with_metaclass(DeclarativeSubBlocksMetaclass, BaseStreamBlock)):
222     pass
223 
224 
225 @python_2_unicode_compatible  # provide equivalent __unicode__ and __str__ methods on Py2
226 class StreamValue(collections.Sequence):
227     """
228     Custom type used to represent the value of a StreamBlock; behaves as a sequence of BoundBlocks
229     (which keep track of block types in a way that the values alone wouldn't).
230     """
231 
232     @python_2_unicode_compatible
233     class StreamChild(BoundBlock):
234         """Provides some extensions to BoundBlock to make it more natural to work with on front-end templates"""
235         def __str__(self):
236             """Render the value according to the block's native rendering"""
237             return self.block.render(self.value)
238 
239         @property
240         def block_type(self):
241             """
242             Syntactic sugar so that we can say child.block_type instead of child.block.name.
243             (This doesn't belong on BoundBlock itself because the idea of block.name denoting
244             the child's "type" ('heading', 'paragraph' etc) is unique to StreamBlock, and in the
245             wider context people are liable to confuse it with the block class (CharBlock etc).
246             """
247             return self.block.name
248 
249     def __init__(self, stream_block, stream_data):
250         self.stream_block = stream_block  # the StreamBlock object that handles this value
251         self.stream_data = stream_data  # a list of (type_name, value) tuples
252         self._bound_blocks = {}  # populated lazily from stream_data as we access items through __getitem__
253 
254     def __getitem__(self, i):
255         if i not in self._bound_blocks:
256             type_name, value = self.stream_data[i]
257             child_block = self.stream_block.child_blocks[type_name]
258             self._bound_blocks[i] = StreamValue.StreamChild(child_block, value)
259 
260         return self._bound_blocks[i]
261 
262     def __len__(self):
263         return len(self.stream_data)
264 
265     def __repr__(self):
266         return repr(list(self))
267 
268     def __str__(self):
269         return self.stream_block.render(self)
270
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/wagtail/wagtailcore/blocks/stream_block.py b/wagtail/wagtailcore/blocks/stream_block.py
--- a/wagtail/wagtailcore/blocks/stream_block.py
+++ b/wagtail/wagtailcore/blocks/stream_block.py
@@ -173,12 +173,12 @@
 
     def to_python(self, value):
         # the incoming JSONish representation is a list of dicts, each with a 'type' and 'value' field.
-        # Convert this to a StreamValue backed by a list of (type, value) tuples
+        # This is passed to StreamValue to be expanded lazily - but first we reject any unrecognised
+        # block types from the list
         return StreamValue(self, [
-            (child_data['type'], self.child_blocks[child_data['type']].to_python(child_data['value']))
-            for child_data in value
+            child_data for child_data in value
             if child_data['type'] in self.child_blocks
-        ])
+        ], is_lazy=True)
 
     def get_prep_value(self, value):
         if value is None:
@@ -246,15 +246,36 @@
             """
             return self.block.name
 
-    def __init__(self, stream_block, stream_data):
+    def __init__(self, stream_block, stream_data, is_lazy=False):
+        """
+        Construct a StreamValue linked to the given StreamBlock,
+        with child values given in stream_data.
+
+        Passing is_lazy=True means that stream_data is raw JSONish data as stored
+        in the database, and needs to be converted to native values
+        (using block.to_python()) when accessed. In this mode, stream_data is a
+        list of dicts, each containing 'type' and 'value' keys.
+
+        Passing is_lazy=False means that stream_data consists of immediately usable
+        native values. In this mode, stream_data is a list of (type_name, value)
+        tuples.
+        """
+        self.is_lazy = is_lazy
         self.stream_block = stream_block  # the StreamBlock object that handles this value
         self.stream_data = stream_data  # a list of (type_name, value) tuples
         self._bound_blocks = {}  # populated lazily from stream_data as we access items through __getitem__
 
     def __getitem__(self, i):
         if i not in self._bound_blocks:
-            type_name, value = self.stream_data[i]
-            child_block = self.stream_block.child_blocks[type_name]
+            if self.is_lazy:
+                raw_value = self.stream_data[i]
+                type_name = raw_value['type']
+                child_block = self.stream_block.child_blocks[type_name]
+                value = child_block.to_python(raw_value['value'])
+            else:
+                type_name, value = self.stream_data[i]
+                child_block = self.stream_block.child_blocks[type_name]
+
             self._bound_blocks[i] = StreamValue.StreamChild(child_block, value)
 
         return self._bound_blocks[i]

{"golden_diff": "diff --git a/wagtail/wagtailcore/blocks/stream_block.py b/wagtail/wagtailcore/blocks/stream_block.py\n--- a/wagtail/wagtailcore/blocks/stream_block.py\n+++ b/wagtail/wagtailcore/blocks/stream_block.py\n@@ -173,12 +173,12 @@\n \n     def to_python(self, value):\n         # the incoming JSONish representation is a list of dicts, each with a 'type' and 'value' field.\n-        # Convert this to a StreamValue backed by a list of (type, value) tuples\n+        # This is passed to StreamValue to be expanded lazily - but first we reject any unrecognised\n+        # block types from the list\n         return StreamValue(self, [\n-            (child_data['type'], self.child_blocks[child_data['type']].to_python(child_data['value']))\n-            for child_data in value\n+            child_data for child_data in value\n             if child_data['type'] in self.child_blocks\n-        ])\n+        ], is_lazy=True)\n \n     def get_prep_value(self, value):\n         if value is None:\n@@ -246,15 +246,36 @@\n             \"\"\"\n             return self.block.name\n \n-    def __init__(self, stream_block, stream_data):\n+    def __init__(self, stream_block, stream_data, is_lazy=False):\n+        \"\"\"\n+        Construct a StreamValue linked to the given StreamBlock,\n+        with child values given in stream_data.\n+\n+        Passing is_lazy=True means that stream_data is raw JSONish data as stored\n+        in the database, and needs to be converted to native values\n+        (using block.to_python()) when accessed. In this mode, stream_data is a\n+        list of dicts, each containing 'type' and 'value' keys.\n+\n+        Passing is_lazy=False means that stream_data consists of immediately usable\n+        native values. In this mode, stream_data is a list of (type_name, value)\n+        tuples.\n+        \"\"\"\n+        self.is_lazy = is_lazy\n         self.stream_block = stream_block  # the StreamBlock object that handles this value\n         self.stream_data = stream_data  # a list of (type_name, value) tuples\n         self._bound_blocks = {}  # populated lazily from stream_data as we access items through __getitem__\n \n     def __getitem__(self, i):\n         if i not in self._bound_blocks:\n-            type_name, value = self.stream_data[i]\n-            child_block = self.stream_block.child_blocks[type_name]\n+            if self.is_lazy:\n+                raw_value = self.stream_data[i]\n+                type_name = raw_value['type']\n+                child_block = self.stream_block.child_blocks[type_name]\n+                value = child_block.to_python(raw_value['value'])\n+            else:\n+                type_name, value = self.stream_data[i]\n+                child_block = self.stream_block.child_blocks[type_name]\n+\n             self._bound_blocks[i] = StreamValue.StreamChild(child_block, value)\n \n         return self._bound_blocks[i]\n", "issue": "Make StreamField lazily fetch related objects\nI have a site that includes a list of pages in the footer (privacy policy, terms and conditions, etc). This is implemented using a `wagtailsettings` model with a join table/InlinePanel to `wagtailcore.Page`. Every page load thus fetches these pages to print their URL and title in the footer.\n\nIt appears that when a page is fetched, any related models referenced in that pages StreamField contents are also fetched. This means that loading the links for the footer of one page means fetching all of the images contained in the content of all of the footer pages. These extra database calls are clearly wasteful.\n\nStreamField instances should lazily fetch related objects when the StreamField is first accessed, instead of as soon as it is loaded.\n\n", "before_files": [{"content": "from __future__ import absolute_import, unicode_literals\n\nimport collections\n\nfrom django import forms\nfrom django.core.exceptions import ValidationError\nfrom django.forms.utils import ErrorList\nfrom django.template.loader import render_to_string\nfrom django.utils.encoding import python_2_unicode_compatible, force_text\nfrom django.utils.html import format_html_join\nfrom django.utils.safestring import mark_safe\n\nimport six\n\nfrom wagtail.wagtailcore.utils import escape_script\n\nfrom .base import Block, DeclarativeSubBlocksMetaclass, BoundBlock\nfrom .utils import indent, js_dict\n\n\n__all__ = ['BaseStreamBlock', 'StreamBlock', 'StreamValue']\n\n\nclass BaseStreamBlock(Block):\n    # TODO: decide what it means to pass a 'default' arg to StreamBlock's constructor. Logically we want it to be\n    # of type StreamValue, but we can't construct one of those because it needs a reference back to the StreamBlock\n    # that we haven't constructed yet...\n    class Meta:\n        @property\n        def default(self):\n            return StreamValue(self, [])\n\n    def __init__(self, local_blocks=None, **kwargs):\n        self._constructor_kwargs = kwargs\n\n        super(BaseStreamBlock, self).__init__(**kwargs)\n\n        self.child_blocks = self.base_blocks.copy()  # create a local (shallow) copy of base_blocks so that it can be supplemented by local_blocks\n        if local_blocks:\n            for name, block in local_blocks:\n                block.set_name(name)\n                self.child_blocks[name] = block\n\n        self.dependencies = self.child_blocks.values()\n\n    def render_list_member(self, block_type_name, value, prefix, index, errors=None):\n        \"\"\"\n        Render the HTML for a single list item. This consists of an <li> wrapper, hidden fields\n        to manage ID/deleted state/type, delete/reorder buttons, and the child block's own HTML.\n        \"\"\"\n        child_block = self.child_blocks[block_type_name]\n        child = child_block.bind(value, prefix=\"%s-value\" % prefix, errors=errors)\n        return render_to_string('wagtailadmin/block_forms/stream_member.html', {\n            'child_blocks': self.child_blocks.values(),\n            'block_type_name': block_type_name,\n            'prefix': prefix,\n            'child': child,\n            'index': index,\n        })\n\n    def html_declarations(self):\n        return format_html_join(\n            '\\n', '<script type=\"text/template\" id=\"{0}-newmember-{1}\">{2}</script>',\n            [\n                (\n                    self.definition_prefix,\n                    name,\n                    mark_safe(escape_script(self.render_list_member(name, child_block.meta.default, '__PREFIX__', '')))\n                )\n                for name, child_block in self.child_blocks.items()\n            ]\n        )\n\n    @property\n    def media(self):\n        return forms.Media(js=['wagtailadmin/js/blocks/sequence.js', 'wagtailadmin/js/blocks/stream.js'])\n\n    def js_initializer(self):\n        # compile a list of info dictionaries, one for each available block type\n        child_blocks = []\n        for name, child_block in self.child_blocks.items():\n            # each info dictionary specifies at least a block name\n            child_block_info = {'name': \"'%s'\" % name}\n\n            # if the child defines a JS initializer function, include that in the info dict\n            # along with the param that needs to be passed to it for initializing an empty/default block\n            # of that type\n            child_js_initializer = child_block.js_initializer()\n            if child_js_initializer:\n                child_block_info['initializer'] = child_js_initializer\n\n            child_blocks.append(indent(js_dict(child_block_info)))\n\n        opts = {\n            'definitionPrefix': \"'%s'\" % self.definition_prefix,\n            'childBlocks': '[\\n%s\\n]' % ',\\n'.join(child_blocks),\n        }\n\n        return \"StreamBlock(%s)\" % js_dict(opts)\n\n    def render_form(self, value, prefix='', errors=None):\n        if errors:\n            if len(errors) > 1:\n                # We rely on ListBlock.clean throwing a single ValidationError with a specially crafted\n                # 'params' attribute that we can pull apart and distribute to the child blocks\n                raise TypeError('ListBlock.render_form unexpectedly received multiple errors')\n            error_list = errors.as_data()[0].params\n        else:\n            error_list = None\n\n        # drop any child values that are an unrecognised block type\n        valid_children = [child for child in value if child.block_type in self.child_blocks]\n\n        list_members_html = [\n            self.render_list_member(child.block_type, child.value, \"%s-%d\" % (prefix, i), i,\n                errors=error_list[i] if error_list else None)\n            for (i, child) in enumerate(valid_children)\n        ]\n\n        return render_to_string('wagtailadmin/block_forms/stream.html', {\n            'label': self.label,\n            'prefix': prefix,\n            'list_members_html': list_members_html,\n            'child_blocks': self.child_blocks.values(),\n            'header_menu_prefix': '%s-before' % prefix,\n        })\n\n    def value_from_datadict(self, data, files, prefix):\n        count = int(data['%s-count' % prefix])\n        values_with_indexes = []\n        for i in range(0, count):\n            if data['%s-%d-deleted' % (prefix, i)]:\n                continue\n            block_type_name = data['%s-%d-type' % (prefix, i)]\n            try:\n                child_block = self.child_blocks[block_type_name]\n            except KeyError:\n                continue\n\n            values_with_indexes.append(\n                (\n                    int(data['%s-%d-order' % (prefix, i)]),\n                    block_type_name,\n                    child_block.value_from_datadict(data, files, '%s-%d-value' % (prefix, i)),\n                )\n            )\n\n        values_with_indexes.sort()\n        return StreamValue(self, [\n            (child_block_type_name, value)\n            for (index, child_block_type_name, value) in values_with_indexes\n        ])\n\n    def clean(self, value):\n        cleaned_data = []\n        errors = []\n        for child in value:  # child is a BoundBlock instance\n            try:\n                cleaned_data.append(\n                    (child.block.name, child.block.clean(child.value))\n                )\n            except ValidationError as e:\n                errors.append(ErrorList([e]))\n            else:\n                errors.append(None)\n\n        if any(errors):\n            # The message here is arbitrary - outputting error messages is delegated to the child blocks,\n            # which only involves the 'params' list\n            raise ValidationError('Validation error in StreamBlock', params=errors)\n\n        return StreamValue(self, cleaned_data)\n\n    def to_python(self, value):\n        # the incoming JSONish representation is a list of dicts, each with a 'type' and 'value' field.\n        # Convert this to a StreamValue backed by a list of (type, value) tuples\n        return StreamValue(self, [\n            (child_data['type'], self.child_blocks[child_data['type']].to_python(child_data['value']))\n            for child_data in value\n            if child_data['type'] in self.child_blocks\n        ])\n\n    def get_prep_value(self, value):\n        if value is None:\n            # treat None as identical to an empty stream\n            return []\n\n        return [\n            {'type': child.block.name, 'value': child.block.get_prep_value(child.value)}\n            for child in value  # child is a BoundBlock instance\n        ]\n\n    def render_basic(self, value):\n        return format_html_join('\\n', '<div class=\"block-{1}\">{0}</div>',\n            [(force_text(child), child.block_type) for child in value]\n        )\n\n    def get_searchable_content(self, value):\n        content = []\n\n        for child in value:\n            content.extend(child.block.get_searchable_content(child.value))\n\n        return content\n\n    def deconstruct(self):\n        \"\"\"\n        Always deconstruct StreamBlock instances as if they were plain StreamBlocks with all of the\n        field definitions passed to the constructor - even if in reality this is a subclass of StreamBlock\n        with the fields defined declaratively, or some combination of the two.\n\n        This ensures that the field definitions get frozen into migrations, rather than leaving a reference\n        to a custom subclass in the user's models.py that may or may not stick around.\n        \"\"\"\n        path = 'wagtail.wagtailcore.blocks.StreamBlock'\n        args = [self.child_blocks.items()]\n        kwargs = self._constructor_kwargs\n        return (path, args, kwargs)\n\n\nclass StreamBlock(six.with_metaclass(DeclarativeSubBlocksMetaclass, BaseStreamBlock)):\n    pass\n\n\n@python_2_unicode_compatible  # provide equivalent __unicode__ and __str__ methods on Py2\nclass StreamValue(collections.Sequence):\n    \"\"\"\n    Custom type used to represent the value of a StreamBlock; behaves as a sequence of BoundBlocks\n    (which keep track of block types in a way that the values alone wouldn't).\n    \"\"\"\n\n    @python_2_unicode_compatible\n    class StreamChild(BoundBlock):\n        \"\"\"Provides some extensions to BoundBlock to make it more natural to work with on front-end templates\"\"\"\n        def __str__(self):\n            \"\"\"Render the value according to the block's native rendering\"\"\"\n            return self.block.render(self.value)\n\n        @property\n        def block_type(self):\n            \"\"\"\n            Syntactic sugar so that we can say child.block_type instead of child.block.name.\n            (This doesn't belong on BoundBlock itself because the idea of block.name denoting\n            the child's \"type\" ('heading', 'paragraph' etc) is unique to StreamBlock, and in the\n            wider context people are liable to confuse it with the block class (CharBlock etc).\n            \"\"\"\n            return self.block.name\n\n    def __init__(self, stream_block, stream_data):\n        self.stream_block = stream_block  # the StreamBlock object that handles this value\n        self.stream_data = stream_data  # a list of (type_name, value) tuples\n        self._bound_blocks = {}  # populated lazily from stream_data as we access items through __getitem__\n\n    def __getitem__(self, i):\n        if i not in self._bound_blocks:\n            type_name, value = self.stream_data[i]\n            child_block = self.stream_block.child_blocks[type_name]\n            self._bound_blocks[i] = StreamValue.StreamChild(child_block, value)\n\n        return self._bound_blocks[i]\n\n    def __len__(self):\n        return len(self.stream_data)\n\n    def __repr__(self):\n        return repr(list(self))\n\n    def __str__(self):\n        return self.stream_block.render(self)\n", "path": "wagtail/wagtailcore/blocks/stream_block.py"}], "after_files": [{"content": "from __future__ import absolute_import, unicode_literals\n\nimport collections\n\nfrom django import forms\nfrom django.core.exceptions import ValidationError\nfrom django.forms.utils import ErrorList\nfrom django.template.loader import render_to_string\nfrom django.utils.encoding import python_2_unicode_compatible, force_text\nfrom django.utils.html import format_html_join\nfrom django.utils.safestring import mark_safe\n\nimport six\n\nfrom wagtail.wagtailcore.utils import escape_script\n\nfrom .base import Block, DeclarativeSubBlocksMetaclass, BoundBlock\nfrom .utils import indent, js_dict\n\n\n__all__ = ['BaseStreamBlock', 'StreamBlock', 'StreamValue']\n\n\nclass BaseStreamBlock(Block):\n    # TODO: decide what it means to pass a 'default' arg to StreamBlock's constructor. Logically we want it to be\n    # of type StreamValue, but we can't construct one of those because it needs a reference back to the StreamBlock\n    # that we haven't constructed yet...\n    class Meta:\n        @property\n        def default(self):\n            return StreamValue(self, [])\n\n    def __init__(self, local_blocks=None, **kwargs):\n        self._constructor_kwargs = kwargs\n\n        super(BaseStreamBlock, self).__init__(**kwargs)\n\n        self.child_blocks = self.base_blocks.copy()  # create a local (shallow) copy of base_blocks so that it can be supplemented by local_blocks\n        if local_blocks:\n            for name, block in local_blocks:\n                block.set_name(name)\n                self.child_blocks[name] = block\n\n        self.dependencies = self.child_blocks.values()\n\n    def render_list_member(self, block_type_name, value, prefix, index, errors=None):\n        \"\"\"\n        Render the HTML for a single list item. This consists of an <li> wrapper, hidden fields\n        to manage ID/deleted state/type, delete/reorder buttons, and the child block's own HTML.\n        \"\"\"\n        child_block = self.child_blocks[block_type_name]\n        child = child_block.bind(value, prefix=\"%s-value\" % prefix, errors=errors)\n        return render_to_string('wagtailadmin/block_forms/stream_member.html', {\n            'child_blocks': self.child_blocks.values(),\n            'block_type_name': block_type_name,\n            'prefix': prefix,\n            'child': child,\n            'index': index,\n        })\n\n    def html_declarations(self):\n        return format_html_join(\n            '\\n', '<script type=\"text/template\" id=\"{0}-newmember-{1}\">{2}</script>',\n            [\n                (\n                    self.definition_prefix,\n                    name,\n                    mark_safe(escape_script(self.render_list_member(name, child_block.meta.default, '__PREFIX__', '')))\n                )\n                for name, child_block in self.child_blocks.items()\n            ]\n        )\n\n    @property\n    def media(self):\n        return forms.Media(js=['wagtailadmin/js/blocks/sequence.js', 'wagtailadmin/js/blocks/stream.js'])\n\n    def js_initializer(self):\n        # compile a list of info dictionaries, one for each available block type\n        child_blocks = []\n        for name, child_block in self.child_blocks.items():\n            # each info dictionary specifies at least a block name\n            child_block_info = {'name': \"'%s'\" % name}\n\n            # if the child defines a JS initializer function, include that in the info dict\n            # along with the param that needs to be passed to it for initializing an empty/default block\n            # of that type\n            child_js_initializer = child_block.js_initializer()\n            if child_js_initializer:\n                child_block_info['initializer'] = child_js_initializer\n\n            child_blocks.append(indent(js_dict(child_block_info)))\n\n        opts = {\n            'definitionPrefix': \"'%s'\" % self.definition_prefix,\n            'childBlocks': '[\\n%s\\n]' % ',\\n'.join(child_blocks),\n        }\n\n        return \"StreamBlock(%s)\" % js_dict(opts)\n\n    def render_form(self, value, prefix='', errors=None):\n        if errors:\n            if len(errors) > 1:\n                # We rely on ListBlock.clean throwing a single ValidationError with a specially crafted\n                # 'params' attribute that we can pull apart and distribute to the child blocks\n                raise TypeError('ListBlock.render_form unexpectedly received multiple errors')\n            error_list = errors.as_data()[0].params\n        else:\n            error_list = None\n\n        # drop any child values that are an unrecognised block type\n        valid_children = [child for child in value if child.block_type in self.child_blocks]\n\n        list_members_html = [\n            self.render_list_member(child.block_type, child.value, \"%s-%d\" % (prefix, i), i,\n                errors=error_list[i] if error_list else None)\n            for (i, child) in enumerate(valid_children)\n        ]\n\n        return render_to_string('wagtailadmin/block_forms/stream.html', {\n            'label': self.label,\n            'prefix': prefix,\n            'list_members_html': list_members_html,\n            'child_blocks': self.child_blocks.values(),\n            'header_menu_prefix': '%s-before' % prefix,\n        })\n\n    def value_from_datadict(self, data, files, prefix):\n        count = int(data['%s-count' % prefix])\n        values_with_indexes = []\n        for i in range(0, count):\n            if data['%s-%d-deleted' % (prefix, i)]:\n                continue\n            block_type_name = data['%s-%d-type' % (prefix, i)]\n            try:\n                child_block = self.child_blocks[block_type_name]\n            except KeyError:\n                continue\n\n            values_with_indexes.append(\n                (\n                    int(data['%s-%d-order' % (prefix, i)]),\n                    block_type_name,\n                    child_block.value_from_datadict(data, files, '%s-%d-value' % (prefix, i)),\n                )\n            )\n\n        values_with_indexes.sort()\n        return StreamValue(self, [\n            (child_block_type_name, value)\n            for (index, child_block_type_name, value) in values_with_indexes\n        ])\n\n    def clean(self, value):\n        cleaned_data = []\n        errors = []\n        for child in value:  # child is a BoundBlock instance\n            try:\n                cleaned_data.append(\n                    (child.block.name, child.block.clean(child.value))\n                )\n            except ValidationError as e:\n                errors.append(ErrorList([e]))\n            else:\n                errors.append(None)\n\n        if any(errors):\n            # The message here is arbitrary - outputting error messages is delegated to the child blocks,\n            # which only involves the 'params' list\n            raise ValidationError('Validation error in StreamBlock', params=errors)\n\n        return StreamValue(self, cleaned_data)\n\n    def to_python(self, value):\n        # the incoming JSONish representation is a list of dicts, each with a 'type' and 'value' field.\n        # This is passed to StreamValue to be expanded lazily - but first we reject any unrecognised\n        # block types from the list\n        return StreamValue(self, [\n            child_data for child_data in value\n            if child_data['type'] in self.child_blocks\n        ], is_lazy=True)\n\n    def get_prep_value(self, value):\n        if value is None:\n            # treat None as identical to an empty stream\n            return []\n\n        return [\n            {'type': child.block.name, 'value': child.block.get_prep_value(child.value)}\n            for child in value  # child is a BoundBlock instance\n        ]\n\n    def render_basic(self, value):\n        return format_html_join('\\n', '<div class=\"block-{1}\">{0}</div>',\n            [(force_text(child), child.block_type) for child in value]\n        )\n\n    def get_searchable_content(self, value):\n        content = []\n\n        for child in value:\n            content.extend(child.block.get_searchable_content(child.value))\n\n        return content\n\n    def deconstruct(self):\n        \"\"\"\n        Always deconstruct StreamBlock instances as if they were plain StreamBlocks with all of the\n        field definitions passed to the constructor - even if in reality this is a subclass of StreamBlock\n        with the fields defined declaratively, or some combination of the two.\n\n        This ensures that the field definitions get frozen into migrations, rather than leaving a reference\n        to a custom subclass in the user's models.py that may or may not stick around.\n        \"\"\"\n        path = 'wagtail.wagtailcore.blocks.StreamBlock'\n        args = [self.child_blocks.items()]\n        kwargs = self._constructor_kwargs\n        return (path, args, kwargs)\n\n\nclass StreamBlock(six.with_metaclass(DeclarativeSubBlocksMetaclass, BaseStreamBlock)):\n    pass\n\n\n@python_2_unicode_compatible  # provide equivalent __unicode__ and __str__ methods on Py2\nclass StreamValue(collections.Sequence):\n    \"\"\"\n    Custom type used to represent the value of a StreamBlock; behaves as a sequence of BoundBlocks\n    (which keep track of block types in a way that the values alone wouldn't).\n    \"\"\"\n\n    @python_2_unicode_compatible\n    class StreamChild(BoundBlock):\n        \"\"\"Provides some extensions to BoundBlock to make it more natural to work with on front-end templates\"\"\"\n        def __str__(self):\n            \"\"\"Render the value according to the block's native rendering\"\"\"\n            return self.block.render(self.value)\n\n        @property\n        def block_type(self):\n            \"\"\"\n            Syntactic sugar so that we can say child.block_type instead of child.block.name.\n            (This doesn't belong on BoundBlock itself because the idea of block.name denoting\n            the child's \"type\" ('heading', 'paragraph' etc) is unique to StreamBlock, and in the\n            wider context people are liable to confuse it with the block class (CharBlock etc).\n            \"\"\"\n            return self.block.name\n\n    def __init__(self, stream_block, stream_data, is_lazy=False):\n        \"\"\"\n        Construct a StreamValue linked to the given StreamBlock,\n        with child values given in stream_data.\n\n        Passing is_lazy=True means that stream_data is raw JSONish data as stored\n        in the database, and needs to be converted to native values\n        (using block.to_python()) when accessed. In this mode, stream_data is a\n        list of dicts, each containing 'type' and 'value' keys.\n\n        Passing is_lazy=False means that stream_data consists of immediately usable\n        native values. In this mode, stream_data is a list of (type_name, value)\n        tuples.\n        \"\"\"\n        self.is_lazy = is_lazy\n        self.stream_block = stream_block  # the StreamBlock object that handles this value\n        self.stream_data = stream_data  # a list of (type_name, value) tuples\n        self._bound_blocks = {}  # populated lazily from stream_data as we access items through __getitem__\n\n    def __getitem__(self, i):\n        if i not in self._bound_blocks:\n            if self.is_lazy:\n                raw_value = self.stream_data[i]\n                type_name = raw_value['type']\n                child_block = self.stream_block.child_blocks[type_name]\n                value = child_block.to_python(raw_value['value'])\n            else:\n                type_name, value = self.stream_data[i]\n                child_block = self.stream_block.child_blocks[type_name]\n\n            self._bound_blocks[i] = StreamValue.StreamChild(child_block, value)\n\n        return self._bound_blocks[i]\n\n    def __len__(self):\n        return len(self.stream_data)\n\n    def __repr__(self):\n        return repr(list(self))\n\n    def __str__(self):\n        return self.stream_block.render(self)\n", "path": "wagtail/wagtailcore/blocks/stream_block.py"}]}