Wagtail: dumpdata command broken for StructBlock

Created on 14 Jan 2017  路  3Comments  路  Source: wagtail/wagtail

Issue Summary

When StructBlock is used in models

Steps to Reproduce

I've found that command is crashed when it tries to export this model:

from wagtail.wagtailcore import blocks
from wagtail.wagtailimages.blocks import ImageChooserBlock

class ImageBlock(blocks.StructBlock):

    image = ImageChooserBlock()
    description = blocks.CharBlock()

    class Meta:
        icon = 'image'
        template = 'image.html'

Just do:

python3 manage.py dumpdata --traceback

And exception occurs:

Traceback (most recent call last):
  File "manage.py", line 22, in <module>
    execute_from_command_line(sys.argv)
  File "C:\Soft\python\venv\lib\site-packages\django\core\management\__init__.py", line 367, in execute_from_command_line
    utility.execute()
  File "C:\Soft\python\venv\lib\site-packages\django\core\management\__init__.py", line 359, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "C:\Soft\python\venv\lib\site-packages\django\core\management\base.py", line 294, in run_from_argv
    self.execute(*args, **cmd_options)
  File "C:\Soft\python\venv\lib\site-packages\django\core\management\base.py", line 345, in execute
    output = self.handle(*args, **options)
  File "C:\Soft\python\venv\lib\site-packages\django\core\management\commands\dumpdata.py", line 200, in handle
    object_count=object_count,
  File "C:\Soft\python\venv\lib\site-packages\django\core\serializers\__init__.py", line 129, in serialize
    s.serialize(queryset, **options)
  File "C:\Soft\python\venv\lib\site-packages\django\core\serializers\base.py", line 88, in serialize
    self.handle_field(obj, field)
  File "C:\Soft\python\venv\lib\site-packages\django\core\serializers\python.py", line 54, in handle_field
    self._current[field.name] = field.value_to_string(obj)
  File "C:\Soft\python\venv\lib\site-packages\wagtail\wagtailcore\fields.py", line 123, in value_to_string
    return self.get_prep_value(value)
  File "C:\Soft\python\venv\lib\site-packages\wagtail\wagtailcore\fields.py", line 107, in get_prep_value
    return json.dumps(self.stream_block.get_prep_value(value), cls=DjangoJSONEncoder)
  File "C:\Soft\python\venv\lib\site-packages\wagtail\wagtailcore\blocks\stream_block.py", line 211, in get_prep_value
    for child in value  # child is a BoundBlock instance
  File "C:\Soft\python\venv\lib\site-packages\wagtail\wagtailcore\blocks\stream_block.py", line 210, in <listcomp>
    {'type': child.block.name, 'value': child.block.get_prep_value(child.value)}
  File "C:\Python35-32\lib\_collections_abc.py", line 815, in __iter__
    v = self[i]
  File "C:\Soft\python\venv\lib\site-packages\wagtail\wagtailcore\blocks\stream_block.py", line 324, in __getitem__
    value = child_block.to_python(raw_value['value'])
  File "C:\Soft\python\venv\lib\site-packages\wagtail\wagtailcore\blocks\struct_block.py", line 131, in to_python
    for name, child_block in self.child_blocks.items()
  File "C:\Soft\python\venv\lib\site-packages\wagtail\wagtailcore\blocks\struct_block.py", line 131, in <listcomp>
    for name, child_block in self.child_blocks.items()
TypeError: argument of type 'int' is not iterable

Technical details

  • Python version: Python 3.5.1
  • Django version: Django (1.10.4)
  • Wagtail version: wagtail (1.8)

Most helpful comment

Hi @soar,

I'm unable to reproduce this on a fresh installation, with this procedure:

  • On the command line:

    wagtail start dumpdatatest
    cd dumpdatatest
    ./manage.py migrate
    ./manage.py createsuperuser
    
  • Edit home/models.py:

    from __future__ import absolute_import, unicode_literals
    
    from django.db import models
    
    from wagtail.wagtailcore.models import Page
    from wagtail.wagtailcore import blocks
    from wagtail.wagtailcore.fields import StreamField
    from wagtail.wagtailimages.blocks import ImageChooserBlock
    from wagtail.wagtailadmin.edit_handlers import FieldPanel, StreamFieldPanel
    
    
    class ImageBlock(blocks.StructBlock):
    
        image = ImageChooserBlock()
        description = blocks.CharBlock()
    
        class Meta:
            icon = 'image'
            template = 'image.html'
    
    
    class HomePage(Page):
        body = StreamField([
            ('image', ImageBlock()),
        ])
    
        content_panels = [
            FieldPanel('title'),
            StreamFieldPanel('body'),
        ]
    
  • On the command line:

    ./manage.py makemigrations  # (use '' as default)
    ./manage.py runserver
    
  • log in to admin, edit homepage, add an image block, publish

  • Run ./manage.py dumpdata --traceback

This produces the dump as expected.

I suspect the error is occurring because your StreamField definition originally had an ordinary ImageChooserBlock, but you changed it to the current StructBlock definition. Changing the StreamField definition does not automatically update the existing page data, so any existing pages will still have the incorrect data type in them.

All 3 comments

Hi @soar,

I'm unable to reproduce this on a fresh installation, with this procedure:

  • On the command line:

    wagtail start dumpdatatest
    cd dumpdatatest
    ./manage.py migrate
    ./manage.py createsuperuser
    
  • Edit home/models.py:

    from __future__ import absolute_import, unicode_literals
    
    from django.db import models
    
    from wagtail.wagtailcore.models import Page
    from wagtail.wagtailcore import blocks
    from wagtail.wagtailcore.fields import StreamField
    from wagtail.wagtailimages.blocks import ImageChooserBlock
    from wagtail.wagtailadmin.edit_handlers import FieldPanel, StreamFieldPanel
    
    
    class ImageBlock(blocks.StructBlock):
    
        image = ImageChooserBlock()
        description = blocks.CharBlock()
    
        class Meta:
            icon = 'image'
            template = 'image.html'
    
    
    class HomePage(Page):
        body = StreamField([
            ('image', ImageBlock()),
        ])
    
        content_panels = [
            FieldPanel('title'),
            StreamFieldPanel('body'),
        ]
    
  • On the command line:

    ./manage.py makemigrations  # (use '' as default)
    ./manage.py runserver
    
  • log in to admin, edit homepage, add an image block, publish

  • Run ./manage.py dumpdata --traceback

This produces the dump as expected.

I suspect the error is occurring because your StreamField definition originally had an ordinary ImageChooserBlock, but you changed it to the current StructBlock definition. Changing the StreamField definition does not automatically update the existing page data, so any existing pages will still have the incorrect data type in them.

You are right, this was my mistake. Sorry for your time @gasman

@gasman So would the easiest solution be to rename the field? Since it doesn't automatically update or is there a way to update or remove the old values from pages they exist on?

Was this page helpful?
0 / 5 - 0 ratings