如何覆盖默认的 wagtail slug 生成?

How to override default wagtail slug generation?

我正在尝试创建一个博客,其中的博客-post 将包含以下内容: example.com/blog/title-01012021/,其中日期 - 是发布日期。 如何覆盖默认的鹡鸰蛞蝓生成?

Wagtail 提供了几种用于 slug 可用性检查和唯一 slug 生成的方法:

def _slug_is_available(slug, parent_page, page=None):
    if parent_page is None:
        # the root page's slug can be whatever it likes...
        return True

    siblings = parent_page.get_children()
    if page:
        siblings = siblings.not_page(page)

    return not siblings.filter(slug=slug).exists()

def _get_autogenerated_slug(self, base_slug):
    candidate_slug = base_slug
    suffix = 1
    parent_page = self.get_parent()

    while not Page._slug_is_available(candidate_slug, parent_page, self):
        # try with incrementing suffix until we find a slug which is available
        suffix += 1
        candidate_slug = "%s-%d" % (base_slug, suffix)

    return candidate_slug

def full_clean(self, *args, **kwargs):
    # Apply fixups that need to happen before per-field validation occurs

    if not self.slug:
        # Try to auto-populate slug from title
        allow_unicode = getattr(settings, 'WAGTAIL_ALLOW_UNICODE_SLUGS', True)
        base_slug = slugify(self.title, allow_unicode=allow_unicode)

        # only proceed if we get a non-empty base slug back from slugify
        if base_slug:
            self.slug = self._get_autogenerated_slug(base_slug)

    if not self.draft_title:
        self.draft_title = self.title

    # Set the locale
    if self.locale_id is None:
        self.locale = self.get_default_locale()

    super().full_clean(*args, **kwargs)

def clean(self):
    super().clean()
    if not Page._slug_is_available(self.slug, self.get_parent(), self):
        raise ValidationError({'slug': _("This slug is already in use")}) 

我不知道如何在我的应用中覆盖这些方法。

您可以使用的一种方法是在模型的保存方法中做一些自定义工作

def some_date_method(self):
    return datetime.datetime.now()


def save(self, *args, **kwargs):
    self.slug = f"{slugify(self.title)}-{self.some_date_method()}"
    super().save(*args, **kwargs)

您可以在保存对象之前使用 Django Signals 更改 slug:

from django.db.models.signals import pre_save
@receiver(pre_save)
def set_slug_on_new_instance(sender, instance, **kwargs):
    if isinstance(instance, Page):
       instance.slug = Whatever value you want

您也可以将 Page 更改为任何您想要为其更换子弹的特定型号。

我找到了适合我的解决方案。 Unidecode 适用于西里尔文段。

from unidecode import unidecode
from django.template import defaultfilters


class HomePage(Page):
    date_published = models.DateField(blank=True, null=True)
    content = .....

    def clean(self):
        super().clean()
        date = '{:%Y-%m-%d}'.format(self.date_published)
        base_slug = defaultfilters.slugify(unidecode(self.title))
        self.slug = "%s-%s" % (base_slug, date)

    date_widget = widgets.AdminDateInput(
        attrs = {
            'placeholder': 'yyyy-mm-dd'
        }
    )

    content_panels = Page.content_panels + [
        FieldPanel('date_published', widget=date_widget),
        StreamFieldPanel('content', classname="full"),
    ]