- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在我的博文模型中,我试图将 RichTextField 迁移到 StreamField。我遵循了 Wagtail 文档“将 RichTextFields 迁移到 StreamField”,包括关于迁移带有修订的博客文章的部分。他们没有效果。如何将 RichTextField 转换为 StreamField?
这是一个使用 Django 1.11.13、Wagtail 2.1 和 PostgreSQL 的博客。我有 200 多篇博文,其中许多处于 Live+Draft 状态,这意味着它们有未发布的修订。我检查了数据库中的博客文章,看起来它们的正文字段存储为 HTML。
我从文档中复制了代码并更改了所有引用以与我自己的项目相关。运行 migrate 后,我收到一个 AttributeError,指出未找到“raw_text”。所以我创建了一个异常(exception)来传递它。我应用了迁移并成功完成。
然后在 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 对象中。
最佳答案
我能够使用此脚本将 RichTextField 迁移到带有 RichTextBlock 的 StreamField(这假设一个架构看起来像 Wagtail 入门教程的前 3 章)。我发现通过将其分解为不同的步骤来考虑此过程更容易:从备份/制作备份、架构迁移、数据迁移和管理/模板更改中获取新数据库。我发现我需要遍历每个 BlogPost 及其所有关联的 PageRevision。编辑实时发布的数据很简单,但草稿存储为两层深的序列化 JSON,很难弄清楚如何与之交互。希望这个脚本可以帮助其他人。注意:此脚本不会反向迁移。
0004_convert_data.py
import json
from django.db import migrations
import wagtail.core.fields
from wagtail.core.rich_text import RichText
def convert_data(apps, schema_editor):
blog_page = apps.get_model('blog', 'BlogPage')
for post in blog_page.objects.all():
print('\n', post.title)
# edit the live post
if post.body.raw_text and not post.body:
post.body = [('paragraph', RichText(post.body.raw_text))]
print('Updated ' + post.title)
post.save()
# edit drafts associated with post
if post.has_unpublished_changes:
print(post.title + ' has drafts...')
for rev in post.revisions.all():
data = json.loads(rev.content_json)
body = data['body']
print(body)
print('This is current JSON:', data, '\n')
data['body'] = json.dumps([{
"type": "paragraph",
"value": body
}])
rev.content_json = json.dumps(data)
print('This is updated JSON:', rev.content_json, '\n')
rev.save()
print('Completed ' + post.title + '.' + '\n')
class Migration(migrations.Migration):
dependencies = [
('blog', '0003_blogpage_stream'),
]
operations = [
migrations.AlterField(
model_name='blogpage',
name='body',
field=wagtail.core.fields.StreamField([('paragraph', wagtail.core.blocks.RichTextBlock())], blank=True),
),
migrations.RunPython(convert_data),
]
模型.py
from django.db import models
from wagtail.core.models import Page
from wagtail.core import blocks
from wagtail.core.fields import RichTextField, StreamField
from wagtail.admin.edit_handlers import FieldPanel, StreamFieldPanel
from wagtail.images.blocks import ImageChooserBlock
from wagtail.search import index
class BlogIndexPage(Page):
intro = RichTextField(blank=True)
content_panels = Page.content_panels + [
FieldPanel('intro', classname="full")
]
class BlogPage(Page):
date = models.DateField("Post date")
intro = models.CharField(max_length=250)
# body = RichTextField(blank=True)
body = StreamField([
('paragraph', blocks.RichTextBlock()),
], blank=True)
stream = StreamField([
('heading', blocks.CharBlock(classname="full title")),
('paragraph', blocks.RichTextBlock()),
('image', ImageChooserBlock()),
], blank=True)
search_fields = Page.search_fields + [
index.SearchField('intro'),
index.SearchField('body'),
]
content_panels = Page.content_panels + [
FieldPanel('date'),
FieldPanel('intro'),
StreamFieldPanel('body'),
StreamFieldPanel('stream'),
]
模板/博客/blog_page.html
{% extends "base.html" %}
{% load wagtailcore_tags %}
{% block body_class %}template-blogpage{% endblock %}
{% block content %}
<h1>{{ page.title }}</h1>
<p class="meta">{{ page.date }}</p>
<div class="intro">{{ page.intro }}</div>
{{ page.body }}
<p><a href="{{ page.get_parent.url }}">Return to blog</a></p>
{% endblock %}
关于wagtail - 如何将 RichTextField 迁移到 StreamField?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55941737/
我有一个 wagtail 非页面模型,我想使用 InlinePanel以便我可以在父表单中内联编辑多个项目。 class Parent(ClusterableModel): panels = [
我有一个使用多站点模式的 wagtail 安装,每个站点有一组用户,每个组都是自己的集合。 当用户登录管理界面时,他们会在摘要部分看到所有集合中的图像计数。 但是当他们点击图像菜单时,他们只能看到他们
我正在关注 the documentation还有this example在我的 Wagtail 站点中创建自定义 OEmbed Finder。 (最终我想修改 YouTube 视频的 HTML 输出
Wagtail 是美妙的 CMS。我确实有一个问题如何在管理员中添加子菜单。我有一个自定义模型位置在那个模型中我有 2 个外键。要管理通过 modeladmin 创建的位置模型,请使用菜单。但是,要管
我很难实现“嵌套类别”之类的东西: PageA: - Cat1 - SubCat1 - SubCat2 - ... - Cat2 - SubCat1 - .
对于博客应用程序或 CMS,这似乎是一个非常简单的要求: 如何自动使登录用户成为 wagtail 页面的作者?例如,如果我以“Bob”身份登录并输入帖子,则作者应自动为“Bob” ". 通常我会简单地
我想从仪表板禁用 wagtail 更新警报。我担心它会惊动我的客户。我很感激你的提醒,但没有办法忽略它。我猜此时唯一的行动方案是进入 wagtail 管理模板并简单地注释掉适用的代码? 最佳答案 有
我在预览 Wagtail 页面时遇到错误,但在发布和实时查看时一切正常。我的设置是这样的: from django.db import models from modelcluster.fields
对于博客应用程序或 CMS,这似乎是一个非常简单的要求: 如何自动使登录用户成为 wagtail 页面的作者?例如,如果我以“Bob”身份登录并输入帖子,则作者应自动为“Bob” ". 通常我会简单地
我想从仪表板禁用 wagtail 更新警报。我担心它会惊动我的客户。我很感激你的提醒,但没有办法忽略它。我猜此时唯一的行动方案是进入 wagtail 管理模板并简单地注释掉适用的代码? 最佳答案 有
我在预览 Wagtail 页面时遇到错误,但在发布和实时查看时一切正常。我的设置是这样的: from django.db import models from modelcluster.fields
url(r'^$', views.HomePage.as_view(), name='homepage'), class HomePage(RedirectView): def get(sel
我正在使用鹡鸰作为 headless CMS。我想让此 CMS 的用户能够轻松查看 SPA 上的页面预览。我已覆盖 API 以在 token 的帮助下公开草稿页面。 我唯一坚持的部分是修改 Previ
有没有办法在 Wagtail 中为 FieldPanel 设置自定义标签?我想做类似的事情: class BlogPage(Page): intro = models.CharField(ma
我试图让两个不同的 Wagtail 站点拥有自己的 404 页面,但似乎没有办法在 wagtail“设置”=>“的“站点”配置中指定哪个页面用作 404 页面站点”部分,当我将它们放入所涉及的应用程序
我正在创建一个 wagtail 站点,用户可以在其中注册、登录到 wagtail 管理员并编写要发布的文章页面。是否有一个钩子(Hook)或可能的方法来拦截和过滤 wagtail 管理中的数据,以便用
我在 Wagtail 2.0 富文本字段中有一堆内容,看起来像 Page heading (intro blurb) heading 1 (heading-1-relevant text) headi
我有一个 Wagtail Page 类的子类,它具有 django ManyToManyField 类型的字段。当我尝试创建页面对象的新实例时,我会获得 ManyToManyField 指向的对象列表
我有一个 Wagtail Page 类的子类,它具有 django ManyToManyField 类型的字段。当我尝试创建页面对象的新实例时,我会获得 ManyToManyField 指向的对象列表
假设我有这样一个模型: class Sandwich(models.Model): """ Food-like things stacked horizontally. """
我是一名优秀的程序员,十分优秀!