【发布时间】:2019-05-01 19:38:32
【问题描述】:
在我的博客文章模型中,我试图将 RichTextField 迁移到 StreamField。我遵循了 Wagtail 文档“将 RichTextFields 迁移到 StreamField”,包括迁移博客文章的部分。他们没有效果。如何将 RichTextField 变成 StreamField?
这是一个使用 Django 1.11.13、Wagtail 2.1 和 PostgreSQL 的博客。我有超过 200 篇博客文章,其中许多都处于 Live+Draft 状态,这意味着它们有未发布的修订版。我检查了数据库中的博客文章,看起来它们的正文字段存储为 HTML。
我复制了文档中的代码并更改了所有引用以与我自己的项目相关。运行 migrate 时,我得到了一个找不到“raw_text”的 AttributeError。所以我创建了一个异常来传递它。我应用了迁移并成功完成。
然后在 models.py 中,我将类的 body 属性从 RichTextField 更改为带有 RichFieldBlock 的 StreamField。我还将其内容面板从 FieldPanel 更改为 StreamFieldPanel。我应用了此迁移,并成功完成。
当我在 Wagtail admin 中查看一些帖子时,所有具有 Live+Draft 状态的帖子都在 StreamFields 中转换为 RichTextBlocks,但是,它们的内容被包装在一个名为 {'rich_text': ''} 的 JSON 对象中。 JSON 对象的样式与编辑器中的其他文本不同。当我实时查看这些帖子时,没有显示任何数据,我认为是因为模板无法读取 JSON。所有具有 Live 状态的博客文章也将 RichTextField 转换为 StreamField,但它们的内容是空的。他们的数据已从编辑器中删除。当我现场观看它们时,它们是空白的。但是,当我在数据库中检查它们时,它们的正文字段仍然包含我之前看到的 HTML。
这是管理员中的 Live+Draft 帖子:
这是管理员中的实时帖子:
在运行两次迁移后,我尝试安装数据库的新副本,但看到奇怪的数据,但这并没有改善情况。
模板.html:
<section>
{{ page.body }}
</section>
在我运行转换迁移之前的models.py:
class BlogPost(Page):
body = RichTextField(blank=True)
content_panels = Page.content_panels + [
FieldPanel('body'),
]
migration.py,我在page_to_streamfield() 函数中为AttributeError 添加了一个异常,因为未找到raw_text:
# -*- coding: utf-8 -*-
# Generated by Django 1.11.13 on 2019-05-01 13:46
from __future__ import unicode_literals
import json
from django.core.serializers.json import DjangoJSONEncoder
from django.db import migrations, models
from wagtail.core.rich_text import RichText
def page_to_streamfield(page):
changed = False
try:
if page.body.raw_text and not page.body:
page.body = [('rich_text', {'rich_text': RichText(page.body.raw_text)})]
changed = True
except AttributeError:
pass
return page, changed
def pagerevision_to_streamfield(revision_data):
changed = False
body = revision_data.get('body')
if body:
try:
json.loads(body)
except ValueError:
revision_data['body'] = json.dumps(
[{
"value": {"rich_text": body},
"type": "rich_text"
}],
cls=DjangoJSONEncoder)
changed = True
else:
# It's already valid JSON. Leave it.
pass
return revision_data, changed
def page_to_richtext(page):
changed = False
if page.body.raw_text is None:
raw_text = ''.join([
child.value['rich_text'].source for child in page.body
if child.block_type == 'rich_text'
])
page.body = raw_text
changed = True
return page, changed
def pagerevision_to_richtext(revision_data):
changed = False
body = revision_data.get('body', 'definitely non-JSON string')
if body:
try:
body_data = json.loads(body)
except ValueError:
# It's not apparently a StreamField. Leave it.
pass
else:
raw_text = ''.join([
child['value']['rich_text'] for child in body_data
if child['type'] == 'rich_text'
])
revision_data['body'] = raw_text
changed = True
return revision_data, changed
def convert(apps, schema_editor, page_converter, pagerevision_converter):
BlogPage = apps.get_model("blog", "BlogPost")
for page in BlogPage.objects.all():
page, changed = page_converter(page)
if changed:
page.save()
for revision in page.revisions.all():
revision_data = json.loads(revision.content_json)
revision_data, changed = pagerevision_converter(revision_data)
if changed:
revision.content_json = json.dumps(revision_data, cls=DjangoJSONEncoder)
revision.save()
def convert_to_streamfield(apps, schema_editor):
return convert(apps, schema_editor, page_to_streamfield, pagerevision_to_streamfield)
def convert_to_richtext(apps, schema_editor):
return convert(apps, schema_editor, page_to_richtext, pagerevision_to_richtext)
class Migration(migrations.Migration):
dependencies = [
# leave the dependency line from the generated migration intact!
('blog', 'previous_migration'),
]
operations = [
migrations.RunPython(
convert_to_streamfield,
convert_to_richtext,
),
]
models.py 运行上一次迁移后,我手动将其更改为 StreamField 并针对此更改运行第二次迁移:
class BlogPost(Page):
body = StreamField([
('rich_text', blocks.RichTextBlock())
], blank=True)
content_panels = Page.content_panels + [
StreamFieldPanel('body'),
]
我希望在 Wagtail 管理员的 StreamField 中看到博客文章的数据,但它是空白的或包装在 JSON 对象中。
【问题讨论】:
标签: wagtail