How to do it...

  1. Open the models.py file from this package in your favorite editor, and add the following content:
# utils/models.py
from enum import Enum
from functools import reduce
from django.db import models

from django.utils.translation import ugettext_lazy as _


class ChoiceEnum(Enum):
@classmethod
def choices(cls):
return tuple((x.name, x.value) for x in cls)


class ItemPropChoiceEnum(ChoiceEnum):
@classmethod
def choices(cls, scope=None):
sources = [cls] + cls.parents()
choices = reduce((lambda x, y: tuple(set(x) | set(y))),
sources)
if scope:
choices = tuple(set(choices) & set(scope.choices()))
return choices

@classmethod
def parents(cls):
return []


class ItemType(ChoiceEnum):
THING = "Thing"
CREATIVE_WORK = "CreativeWork"
BOOK = "Book"


class BooleanFieldItemProp(ItemPropChoiceEnum):
ABRIDGED = "abridged"


class CharFieldItemProp(ItemPropChoiceEnum):
ACCESS_MODE = "accessMode"
ALTERNATE_NAME = "alternateName"
BOOK_EDITION = "bookEdition"
DESCRIPTION = "description"
HEADLINE = "headline"


class TextFieldItemProp(ItemPropChoiceEnum):
@classmethod
def parents(cls):
return [CharFieldItemProp]


class ForeignKeyItemProp(ItemPropChoiceEnum):
ABOUT = "about"
SUBJECT_OF = "subjectOf"
WORK_EXAMPLE = "workExample"
WORK_TRANSLATION = "workTranslation"


class ManyToManyFieldItemProp(ItemPropChoiceEnum):
@classmethod
def parents(cls):
return [ForeignKeyItemProp]


class OneToOneFieldItemProp(ItemPropChoiceEnum):
def parents(self):
return [ForeignKeyItemProp]


class UrlFieldItemProp(ItemPropChoiceEnum):
ADDITIONAL_TYPE = "additionalType"
SAME_AS = "sameAs"
URL = "url"


class SchemaMicrodata(models.Model):
class Meta:
abstract = True

@classmethod
def itemprop_fields(cls):
return []

itemtype = models.CharField(_("Microdata item type"),
max_length=100,
blank=True,
choices=ItemType.choices())

def itemtype_attribute(self):
attr = loader.render_to_string(
"utils/itemtype.attr.html",
{"itemtype": self.get_itemtype_display()})
return mark_safe(attr)
  1. Then, add a signals.py file to the demo_app, with the following content:
# demo_app/signals.py
from django.db.models import CharField
from django.db.models.signals import class_prepared
from django.dispatch import receiver
from django.template import loader
from django.utils.safestring import mark_safe

from utils import models


@receiver(class_prepared)
def augment_with_itemprops_microdata(sender, **kwargs):
if issubclass(sender, models.SchemaMicrodata):
for field_name in sender.itemprop_fields():
field = None
for fld in sender._meta.fields:
if fld.get_attname() == field_name:
field = fld
type = field.__class__.__name__ if field else "None"
enum = getattr(models, f"{type}ItemProp", None)
if enum:
display_name = field.verbose_name or field.name
itemprop_field_name = f"{field.name}_itemprop"
itemprop_field = CharField(
f"{display_name} microdata item property",
name=itemprop_field_name,
max_length=200,
unique=False,
blank=True,
null=False,
default="",
editable=True,
choices=enum.choices(),
db_tablespace=field.db_tablespace)
itemprop_field.auto_created = True
itemprop_field.contribute_to_class(
sender,
itemprop_field_name)

def itemprop_attr(sender_instance):
prop_key = getattr(sender_instance,
itemprop_field_name,
None)
prop_val = field.choices
attr = loader.render_to_string(
"utils/itemprop.attr.html",
{"itemprop": getattr(sender_instance,
itemprop_field_name,
None)})
return mark_safe(attr)

setattr(sender,
f"{itemprop_field_name}_attribute",
property(itemprop_attr))
  1. To load the signals at the right time, we have to provide a custom app configuration. We build the config in demo_app/apps.py, as follows:
# demo_app/apps.py
from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _


class DemoAppConfig(AppConfig):
name = "demo_app"
verbose_name = _("Demo App")

def ready(self):
from . import signals

This configuration is enabled by setting it as the app's default, as follows:

# demo_app/__init__.py
default_app_config = "demo_app.apps.DemoAppConfig"
  1. In the templates/utils directory, add an itemtype.attr.html file, as follows:
{# utils/itemtype.attr.html #}
{% if itemtype %}
itemscope itemtype="//schema.org/{{ itemtype }}"{% endif %}

Also, create an itemprop.attr.html file, as follows:

{# utils/itemprop.attr.html #}
{% if itemprop %}
itemprop="{{ itemprop }}"{% endif %}
  1. Finally, we just need to make use of the mixin in the demo_app/models.py:
# demo_app/models.py
# ...
from utils.models import SchemaMicrodata


class Idea(SchemaMicrodata):
# ...
@classmethod
def itemprop_fields(cls):
return ["title", "content"] + super().itemprop_fields()
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.64.132