Field Inheritance¶
Content can inherit field values from content it references. The REST API response of the referencing object is filled up with the values of the referenced object, without copying any data into the database.
The classic example is the MemberBlock: it references a Contact and shows that contact’s
name, address and opening hours, while still being able to override single fields locally.
Which fields inherit is configured declaratively — per field, with the inherit: supermodel
namespace.
Rules¶
A field only inherits while the referencing object has no own value for it. Any value entered locally wins.
The referenced object is resolved through a relation field on the referencing object. If the reference is empty or broken, nothing is inherited.
Values are only inherited if the current user may view the referenced object, and only for fields the user may read.
The source object must have a field of the same name. Fields without a counterpart are silently skipped.
With the Inherit field data behavior enabled, editors get a checkbox to switch inheritance off per object.
Configuring inheritable fields¶
Single fields¶
Add inherit:from="<relation field name>" to a field in the supermodel XML. The value names
the relation field that points to the source object:
<model xmlns="http://namespaces.plone.org/supermodel/schema"
xmlns:inherit="http://namespaces.webcloud7.ch/supermodel/inherit">
<schema>
<field name="badge" type="zope.schema.TextLine" inherit:from="contact">
<title>Badge</title>
<required>False</required>
</field>
</schema>
</model>
badge now inherits from the object referenced by the contact relation field — provided the
referenced type has a badge field too.
A whole schema¶
Put the attribute on the <schema> node to make every field of that schema inherit:
<model xmlns="http://namespaces.plone.org/supermodel/schema"
xmlns:inherit="http://namespaces.webcloud7.ch/supermodel/inherit">
<schema inherit:from="contact">
<field name="slogan" type="zope.schema.TextLine">
<title>Slogan</title>
</field>
<field name="motto" type="zope.schema.TextLine">
<title>Motto</title>
</field>
</schema>
</model>
Single fields can still be configured explicitly; an inherit:from on a field overrules the
one on its schema.
In Python schemas¶
Behaviors written in Python use the inherit_from directive, which does the same thing:
from wcs.backend.inheritance.directives import inherit_from
class ITeamCard(model.Schema):
inherit_from('contact') # all fields of this schema
inherit_from('contact', 'slogan', 'motto') # or only the named ones
slogan = schema.TextLine(title=_('label_slogan', default='Slogan'))
Enabling it for a content type¶
Inheritance is applied by the REST API serializer of the content type. For a new type, register
a serializer that mixes FieldInheritanceMixin into the serializer the type would use anyway:
@implementer(ISerializeToJson)
@adapter(ITeamCard, Interface)
class TeamCardSerializer(FieldInheritanceMixin, DefaultBlockSerializer):
""""""
<adapter factory=".restapi.TeamCardSerializer" />
Add the Inherit field data behavior to the type if editors should be able to switch inheritance off.
REST API¶
Inherited values appear as ordinary field values — consumers cannot tell them apart from values stored on the object itself:
const response = await fetch('https://example.org/++api++/a-page/my-member-block', {
headers: { Accept: 'application/json' },
});
const block = await response.json();
block.lastname; // from the block, or inherited from the contact
block.badge; // XML configured field, same behaviour
block.inherit_data; // false if inheritance was switched off for this block
Setting inherit_data to false returns only the values stored on the object:
await fetch('https://example.org/++api++/a-page/my-member-block', {
method: 'PATCH',
headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
body: JSON.stringify({ inherit_data: false }),
});