Repository: wagtail/wagtail

Issue:
Pictures in StreamField cannot be put into order
The problem can be reproduced with the following model:

``` python
class Homepage(Page):
    body = StreamField([
        (
            'portrait', blocks.StructBlock([
                ('title', blocks.CharBlock()),
                ('name', blocks.CharBlock()),
                ('portrait', blocks.ListBlock(blocks.StructBlock([
                    ('image', ImageChooserBlock()),
                    ('name', blocks.CharBlock()),
                    ('link', blocks.CharBlock(required=False)),
                    ('text', blocks.RichTextBlock()),
                    ])
                )
                )
            ])
        ),
    ])

Homepage.content_panels = [
    FieldPanel('title'),
    StreamFieldPanel('body'),
]
```

In wagtail admin, add a portrait structblock(`'portrait', blocks.StructBlock`), then add 11 listblocks(`'portrait', blocks.ListBlock()`) to it. Then the last listblock will appear in the third position and there is no way to put them in order.

Environment:
django 1.7.7
wagtail 1.0b1



Discussion:
Ack... that'll be because we're ordering ListBlock items alphabetically so that '11' comes before '2'. We fixed this for StreamBlock, but apparently forgot to fix it here too...

https://github.com/torchbox/wagtail/blob/master/wagtail/wagtailcore/blocks/list_block.py#L102
https://github.com/torchbox/wagtail/blob/master/wagtail/wagtailcore/blocks/stream_block.py#L142

Thanks for the report!


Resolving patch:
diff --git a/wagtail/wagtailcore/blocks/list_block.py b/wagtail/wagtailcore/blocks/list_block.py
--- a/wagtail/wagtailcore/blocks/list_block.py
+++ b/wagtail/wagtailcore/blocks/list_block.py
@@ -99,7 +99,7 @@ def value_from_datadict(self, data, files, prefix):
                 continue
             values_with_indexes.append(
                 (
-                    data['%s-%d-order' % (prefix, i)],
+                    int(data['%s-%d-order' % (prefix, i)]),
                     self.child_block.value_from_datadict(data, files, '%s-%d-value' % (prefix, i))
                 )
             )


Test patch:
diff --git a/wagtail/wagtailcore/tests/test_blocks.py b/wagtail/wagtailcore/tests/test_blocks.py
--- a/wagtail/wagtailcore/tests/test_blocks.py
+++ b/wagtail/wagtailcore/tests/test_blocks.py
@@ -609,6 +609,36 @@ class LinkBlock(blocks.StructBlock):
 
         self.assertEqual(content, ["Wagtail", "Django"])
 
+    def test_ordering_in_form_submission_uses_order_field(self):
+        block = blocks.ListBlock(blocks.CharBlock())
+
+        # check that items are ordered by the 'order' field, not the order they appear in the form
+        post_data = {'shoppinglist-count': '3'}
+        for i in range(0, 3):
+            post_data.update({
+                'shoppinglist-%d-deleted' % i: '',
+                'shoppinglist-%d-order' % i: str(2 - i),
+                'shoppinglist-%d-value' % i: "item %d" % i
+            })
+
+        block_value = block.value_from_datadict(post_data, {}, 'shoppinglist')
+        self.assertEqual(block_value[2], "item 0")
+
+    def test_ordering_in_form_submission_is_numeric(self):
+        block = blocks.ListBlock(blocks.CharBlock())
+
+        # check that items are ordered by 'order' numerically, not alphabetically
+        post_data = {'shoppinglist-count': '12'}
+        for i in range(0, 12):
+            post_data.update({
+                'shoppinglist-%d-deleted' % i: '',
+                'shoppinglist-%d-order' % i: str(i),
+                'shoppinglist-%d-value' % i: "item %d" % i
+            })
+
+        block_value = block.value_from_datadict(post_data, {}, 'shoppinglist')
+        self.assertEqual(block_value[2], "item 2")
+
 
 class TestStreamBlock(unittest.TestCase):
     def test_initialisation(self):
@@ -825,7 +855,7 @@ class ArticleBlock(blocks.StreamBlock):
         block = ArticleBlock()
         self.assertIn('<script type="text/x-html-template">hello world</script>', block.all_html_declarations())
 
-    def test_ordering_in_form_submission(self):
+    def test_ordering_in_form_submission_uses_order_field(self):
         class ArticleBlock(blocks.StreamBlock):
             heading = blocks.CharBlock()
             paragraph = blocks.CharBlock()
@@ -845,6 +875,13 @@ class ArticleBlock(blocks.StreamBlock):
         block_value = block.value_from_datadict(post_data, {}, 'article')
         self.assertEqual(block_value[2].value, "heading 0")
 
+    def test_ordering_in_form_submission_is_numeric(self):
+        class ArticleBlock(blocks.StreamBlock):
+            heading = blocks.CharBlock()
+            paragraph = blocks.CharBlock()
+
+        block = ArticleBlock()
+
         # check that items are ordered by 'order' numerically, not alphabetically
         post_data = {'article-count': '12'}
         for i in range(0, 12):