ヘッドレスキグテール、何が痛みポイントですか?
熟したNCCで昨年、我々は書き直しましたRIPE Labs Wagtail、Djangoに基づいてCMSを使用します.それは、Djangoテンプレートでサーバー側レンダリングHTMLを吐き出すモノリシックアプリケーションで終わりました.
今年、我々はWagtailを我々の書換えに再訪問していますmain site そして、私はバックエンドとフロントエンドのデカップリングを提案しました.
このような構造を提案したのは、次のような反応とメタフレームワークを利用することである.JSまたはギャツビー.それは私がよりよく知っているものであるので、私はほとんど反応の点で話します、しかし、我々もVueを評価しました、そして、それは等しくよく適用されます.
そのようなプロジェクトをどのように設定するかをよりよく理解するためにThe Definitive Guide to Next.js and Wagtail マイケルYinとこれによってboilerplate repo フロジュによって.私はあなたがレポ最初にチェックアウトをお勧めし、本を得る場合は、さらに説明が必要です.
この一連のポストでは、WagtailとプロジェクトをヘッドレスCMSとして設定する方法を紹介します.フロントエンドのJS私は痛みのポイントを強調するために最善を尽くしますので、このセットアップの正直な評価を出すことができます.
Here's a link to the companion repo that contains all the code from these posts .
あなたが熟したNCCで我々の選択について興味があるならば、我々は今度もdjangoテンプレートを使います.
JavaScriptフレームワークを使う理由は?
まず最初に、なぜ私はJavaScriptのフレームワークを使用したいのですか?両方のアプローチの良い理由があります.
UIを再利用可能なコンポーネントに分解すると、一貫性のあるUIの開発が容易になります.さらに、カプセル化されたコンポーネントは個々にテストするのがより簡単です、そして、あなたがDjangoテンプレートエンジンが決してキャッチしないビルド時間で、あなたがエラーを捕えますtypescriptの助けを借りて.
フリップ側は、それが少し複雑さを増やすということです:Djangoテンプレートは、セッションと認証のようなジャンゴの他のすべての特徴で、箱から働きます.
第二に、次のようなメタフレームワーク.JSまたはGatsbyはDXのテンプレートよりもはるかに良い、ローカルのフロントエンドの開発に大きなDXを提供します.より重要なのは、事前にページをレンダリングし、静的なビルドを生産する彼らの能力は、ヘッドレスのCMSに最適です.
ワタシからのJSONのサービング
を、十分な話!何をする必要がありますあなたのWagtailセットアップでそれを完全にヘッドレスに変更する必要がありますか?
ワタシはan optional module これは公開、読み取り専用、JSONフォーマットAPIを公開します.しかし、それは最も直感的ではない、それはまだすべてのあなたのページのHTMLテンプレートを仮定します.
デフォルトでは
例えば、パスを持つページ
ヘッダーでの要求の下の実装で
Wagtailのリッチテキストのレンダリング
WagtailはJSON API用の組み込みモジュールを持っているので、それらのシリアライザーを再利用できると思います
内部オブジェクトの表現は次のようになります.
それで、あなたは
Django RESTフレームワークによるページ直列化器の記述
JSONを吐き出す前に必要な最後のものはシリアライザーです.serializersとは何ですか?
我々の要約のためにシリアライザーを作成することによって、行動でそれを見ましょう
しかし、Wagtailページの主要なビルディングブロックのうちの1つは
すべてをまとめる
すべてと言われて、私たちのサイトに記事を追加するページモデルを作成しましょう.私たちの記事は今のところ簡単になります:彼らは要約と本文と豊富なテキストとイメージがあります.
以来
私たちは 私たちは イン クラス名を返します 最終結果は
結論
これは私のガイドの最初の部分で、WagtailをヘッドレスCMSとして走らせています.この最初の部分では、Wagtailの既定の動作をテンプレートのレンダリングの代わりにJSONを返すように変更する方法を見ました.
このガイドの次のインストールでは、このJSON APIを消費するフロントエンドを設定する方法を詳しく見ていきます.
もともとブログで投稿しました.https://tommasoamici.com/blog/headless-wagtail-what-are-the-pain-points
今年、我々はWagtailを我々の書換えに再訪問していますmain site そして、私はバックエンドとフロントエンドのデカップリングを提案しました.
このような構造を提案したのは、次のような反応とメタフレームワークを利用することである.JSまたはギャツビー.それは私がよりよく知っているものであるので、私はほとんど反応の点で話します、しかし、我々もVueを評価しました、そして、それは等しくよく適用されます.
そのようなプロジェクトをどのように設定するかをよりよく理解するためにThe Definitive Guide to Next.js and Wagtail マイケルYinとこれによってboilerplate repo フロジュによって.私はあなたがレポ最初にチェックアウトをお勧めし、本を得る場合は、さらに説明が必要です.
この一連のポストでは、WagtailとプロジェクトをヘッドレスCMSとして設定する方法を紹介します.フロントエンドのJS私は痛みのポイントを強調するために最善を尽くしますので、このセットアップの正直な評価を出すことができます.
Here's a link to the companion repo that contains all the code from these posts .
あなたが熟したNCCで我々の選択について興味があるならば、我々は今度もdjangoテンプレートを使います.
JavaScriptフレームワークを使う理由は?
まず最初に、なぜ私はJavaScriptのフレームワークを使用したいのですか?両方のアプローチの良い理由があります.
UIを再利用可能なコンポーネントに分解すると、一貫性のあるUIの開発が容易になります.さらに、カプセル化されたコンポーネントは個々にテストするのがより簡単です、そして、あなたがDjangoテンプレートエンジンが決してキャッチしないビルド時間で、あなたがエラーを捕えますtypescriptの助けを借りて.
フリップ側は、それが少し複雑さを増やすということです:Djangoテンプレートは、セッションと認証のようなジャンゴの他のすべての特徴で、箱から働きます.
第二に、次のようなメタフレームワーク.JSまたはGatsbyはDXのテンプレートよりもはるかに良い、ローカルのフロントエンドの開発に大きなDXを提供します.より重要なのは、事前にページをレンダリングし、静的なビルドを生産する彼らの能力は、ヘッドレスのCMSに最適です.
ワタシからのJSONのサービング
を、十分な話!何をする必要がありますあなたのWagtailセットアップでそれを完全にヘッドレスに変更する必要がありますか?
ワタシはan optional module これは公開、読み取り専用、JSONフォーマットAPIを公開します.しかし、それは最も直感的ではない、それはまだすべてのあなたのページのHTMLテンプレートを仮定します.
デフォルトでは
wagtail.core.Page
ページのレンダリングに関するメソッド serve
, を返します.TemplateResponse
Wagtail 2.16.1現在.class Page(...):
...
def serve(self, request, *args, **kwargs):
request.is_preview = getattr(request, "is_preview", False)
return TemplateResponse(
request,
self.get_template(request, *args, **kwargs),
self.get_context(request, *args, **kwargs),
)
私は、すべてのWagtail/api/
このメソッドをオーバーライドして代わりにJSONを返します.このように、あなたのフロントエンドパスはあなたのヘッドレスCMSで1 : 1をマップできます.別のサブドメインでWagtailを実行することもできます.例えば、パスを持つページ
/careers
が一致する/api/careers
WagtailからJSON形式でページの内容を返します.ヘッダーでの要求の下の実装で
Content-Type: application/json
to /api/careers
JSONを受け付けないリクエストは、JSONレスポンスを受け取ります/careers
.# models.py
class BasePage(Page):
class Meta:
abstract = True
...
def serve(self, request, *args, **kwargs):
"""
If the request accepts JSON, return an object with all
the page's data. Otherwise redirect to the rendered frontend.
"""
if request.content_type == "application/json":
# this is very important, we'll see why later
response = self.serialize_page()
return JsonResponse(response)
else:
full_path = request.get_full_path()
return HttpResponseRedirect(
urllib.parse.urljoin(
settings.BASE_URL,
full_path.replace("/api", ""),
)
)
これが動作する前に、Django RESTフレームワークを使用してカスタムSerializersを定義する必要があります.ほとんどの部分については、これは大きな取引は、我々はlast section , リッチテキストではいくつかの調整が必要です.Wagtailのリッチテキストのレンダリング
WagtailはJSON API用の組み込みモジュールを持っているので、それらのシリアライザーを再利用できると思います
StreamField
!), しかし、そうすることでリッチテキストの内部データベース表現が返されます.内部オブジェクトの表現は次のようになります.
<!-- Link to another page -->
<a linktype="page" id="3">Contact us</a>
<!-- Embedded image -->
<embed embedtype="image" id="10" alt="A pied wagtail" format="left" />
実際のURLと画像は、|richtext
テンプレートフィルタexpand_db_html
機能からwagtail.core.rich_text
.それで、あなたは
get_api_representation
メソッドRichTextBlock
このように# blocks.py
from wagtail.core.blocks import RichTextBlock
from wagtail.core.rich_text import expand_db_html
class CustomRichTextBlock(RichTextBlock):
def get_api_representation(self, value, context=None):
return expand_db_html(value.source).replace("/api", "")
同様にRichTextField
, 次のようにカスタムフィールドシリアライザーを使います.# fields.py
from rest_framework.fields import Field
from wagtail.core.rich_text import expand_db_html
class CustomRichTextField(Field):
def to_representation(self, value):
return expand_db_html(value).replace("/api", "")
あなたがprependedしたならば、注意してください/api
Wagtail URLには、フロントエンドでレンダリングするときにプレフィックスを削除します.Django RESTフレームワークによるページ直列化器の記述
JSONを吐き出す前に必要な最後のものはシリアライザーです.serializersとは何ですか?
Serializers allow complex data such as querysets and model instances to be converted to native Python datatypes that can then be easily rendered into JSON
我々の要約のためにシリアライザーを作成することによって、行動でそれを見ましょう
BasePage
. すべてのモデルがこのクラスから継承するので、すべてのページが同じメタデータを返すように、ここで一般のフィールドを加えることができます.# serializers.py
from rest_framework import serializers
from .models import BasePage
class BasePageSerializer(serializers.ModelSerializer):
class Meta:
model = BasePage
fields = ("id", "slug", "title", "url", "first_published_at")
これまでのところ、これらのフィールドをシリアル化するのは簡単です.なぜなら、これらのフィールドは文字列、整数、そしてdatetimeオブジェクトです.しかし、Wagtailページの主要なビルディングブロックのうちの1つは
StreamField
そして、ジャンゴは箱からそれを扱うことができません、しかし、幸運にもワタシはそうすることができます.シリアル化を更新しましょうStreamField
フィールド.# serializers.py
from rest_framework import serializers
from wagtail.api.v2 import serializers as wagtail_serializers
from wagtail.core import fields
from .models import BasePage
class BasePageSerializer(serializers.ModelSerializer):
serializer_field_mapping = serializers.ModelSerializer.serializer_field_mapping.copy()
serializer_field_mapping.update({
fields.StreamField: wagtail_serializers.StreamField,
})
class Meta:
model = BasePage
fields = ("id", "slug", "title", "url", "first_published_at")
我々は今我々が我々の最初の非抽象モデルを作成するために必要なすべてを持っています.すべてをまとめる
すべてと言われて、私たちのサイトに記事を追加するページモデルを作成しましょう.私たちの記事は今のところ簡単になります:彼らは要約と本文と豊富なテキストとイメージがあります.
# models.py
from wagtail.core.fields import StreamField
from wagtail.images.blocks import ImageChooserBlock
from .blocks import CustomRichTextBlock
...
class ArticlePage(BasePage):
summary = models.CharField(max_length=300)
body = StreamField(
[
("paragraph", CustomRichTextBlock()),
("image", ImageChooserBlock(icon="image")),
],
)
content_panels = [
FieldPanel("title"),
FieldPanel("summary", widget=forms.Textarea(attrs={"rows": "4"})),
StreamFieldPanel("body"),
]
我々が加える各々のモデルがそれ自身のシリアライザーを必要とするのを思い出してください.を加えましょうArticlePageSerializer
です.なぜなら、モデルはBasePage
, 我々は、拡張する必要がありますMeta.fields
2つの新しいフィールドをArticlePage
.以来
summary
文字列は、ジャンゴレストは自動的に処理されます以降body
はStreamField
, BasePageSerializer
既にそれを処理する方法を知っている.# serializers.py
from .models import ArticlePage
...
class ArticlePageSerializer(BasePageSerializer):
class Meta:
model = ArticlePage
fields = BasePageSerializer.Meta.fields + (
"summary",
"body",
)
これを実行してみたらエラーが出ます.我々は定義していないserialize_page
メソッドオンBasePage
. 我々は今それを書くつもりです、そして、それはパズルの最も重要な部分です.# models.py
class BasePage(Page):
...
serializer_class = None
def serialize_page(self):
if not self.serializer_class:
raise Exception(
f"serializer_class is not set {self.__class__.__name__}",
)
serializer_class = import_string(self.serializer_class)
return {
"type": self.__class__.__name__,
"data": serializer_class(self).data,
}
...
class ArticlePage(BasePage):
serializer_class = "your_app.serializers.ArticlePageSerializer"
...
ここにたくさん行くので、私はそれを壊させてください.serializer_class
プロパティNone
Serializersとしてデフォルトでは抽象モデルでは動作しません.serializer_class
プロパティArticlePage
への道ArticlePageSerializer
前に付け加えた.serialize_page
シリアライザーを動的にインポートし、現在のオブジェクトをシリアル化します."type"
, このガイドの次の部分でこれ以上.serialize_page
これらの行に沿って辞書を返します.{
"type": "ArticlePage",
"data": {
"id": 3,
"slug": "my-article",
"title": "My article",
"url": "/api/my-article/",
"first_published_at": "2022-02-25T15:14:13.030300Z",
"summary": "My article's summary",
"body": [
{
"type": "paragraph",
"value": "<p data-block-key=\"itzwt\">This is my article</p>",
"id": "4519e337-b467-44dd-a075-d2db4df0f0c8"
}
]
}
}
And BasePage.serve
リクエストを送信する場合、JSONフォームでそれを返します/api/my-article
.結論
これは私のガイドの最初の部分で、WagtailをヘッドレスCMSとして走らせています.この最初の部分では、Wagtailの既定の動作をテンプレートのレンダリングの代わりにJSONを返すように変更する方法を見ました.
このガイドの次のインストールでは、このJSON APIを消費するフロントエンドを設定する方法を詳しく見ていきます.
もともとブログで投稿しました.https://tommasoamici.com/blog/headless-wagtail-what-are-the-pain-points
Reference
この問題について(ヘッドレスキグテール、何が痛みポイントですか?), 我々は、より多くの情報をここで見つけました https://dev.to/tommasoamici/headless-wagtail-what-are-the-pain-points-ji4テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol