Разработка кастомных Snippets Wagtail

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Разработка кастомных Snippets Wagtail
Средняя
от 1 рабочего дня до 3 рабочих дней
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    874
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    851

Разработка кастомных Snippets Wagtail

Snippets в Wagtail — это модели Django, зарегистрированные в административной панели как управляемые объекты контента. В отличие от страниц, сниппеты не имеют URL и не участвуют в дереве сайта. Их используют для переиспользуемых фрагментов: меню, баннеров, контактных данных, команды, партнёров, отзывов — всего, что нужно в разных местах сайта независимо от структуры страниц.

Регистрация сниппета

# models.py
from django.db import models
from wagtail.snippets.models import register_snippet
from wagtail.admin.panels import FieldPanel, MultiFieldPanel
from wagtail.fields import RichTextField


@register_snippet
class Testimonial(models.Model):
    author_name = models.CharField('Имя', max_length=100)
    author_title = models.CharField('Должность', max_length=100, blank=True)
    author_photo = models.ForeignKey(
        'wagtailimages.Image',
        null=True, blank=True,
        on_delete=models.SET_NULL,
        related_name='+'
    )
    text = RichTextField('Текст отзыва', features=['bold', 'italic'])
    rating = models.PositiveSmallIntegerField('Оценка', default=5)
    is_featured = models.BooleanField('Показывать на главной', default=False)

    panels = [
        MultiFieldPanel([
            FieldPanel('author_name'),
            FieldPanel('author_title'),
            FieldPanel('author_photo'),
        ], heading='Автор'),
        FieldPanel('text'),
        FieldPanel('rating'),
        FieldPanel('is_featured'),
    ]

    def __str__(self):
        return f'{self.author_name} — {self.rating}★'

    class Meta:
        verbose_name = 'Отзыв'
        verbose_name_plural = 'Отзывы'
        ordering = ['-is_featured', '-id']

ViewSetGroup для группировки в меню

Начиная с Wagtail 4.1 сниппеты регистрируются через SnippetViewSet — это даёт полный контроль над поведением в админке:

from wagtail.snippets.views.snippets import SnippetViewSet, SnippetViewSetGroup
from wagtail.snippets.models import register_snippet


class TestimonialViewSet(SnippetViewSet):
    model = Testimonial
    icon = 'comment'
    menu_label = 'Отзывы'
    menu_name = 'testimonials'
    list_display = ['author_name', 'author_title', 'rating', 'is_featured']
    list_filter = ['is_featured', 'rating']
    search_fields = ['author_name', 'text']
    ordering = ['-is_featured', '-id']


class TeamMemberViewSet(SnippetViewSet):
    model = TeamMember
    icon = 'user'
    menu_label = 'Команда'
    menu_name = 'team'
    list_display = ['full_name', 'position', 'department']
    list_filter = ['department']


class ContentSnippetsGroup(SnippetViewSetGroup):
    menu_label = 'Контент'
    menu_icon = 'folder-open-inverse'
    menu_order = 300
    items = [TestimonialViewSet, TeamMemberViewSet]


register_snippet(ContentSnippetsGroup)

Сниппет с историей версий

from wagtail.models import DraftStateMixin, RevisionMixin, PreviewableMixin
from wagtail.admin.panels import PublishingPanel


@register_snippet
class SiteAnnouncement(DraftStateMixin, RevisionMixin, PreviewableMixin, models.Model):
    title = models.CharField(max_length=200)
    body = RichTextField()
    show_from = models.DateTimeField(null=True, blank=True)
    show_until = models.DateTimeField(null=True, blank=True)
    is_dismissible = models.BooleanField(default=True)

    panels = [
        FieldPanel('title'),
        FieldPanel('body'),
        FieldPanel('show_from'),
        FieldPanel('show_until'),
        FieldPanel('is_dismissible'),
        PublishingPanel(),
    ]

    def get_preview_template(self, request, mode_name):
        return 'previews/announcement.html'

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = 'Объявление'
        verbose_name_plural = 'Объявления'

DraftStateMixin добавляет черновики и публикацию. RevisionMixin — историю версий с возможностью отката. PreviewableMixin — кнопку предпросмотра в редакторе.

Использование сниппетов в StreamField

from wagtail.snippets.blocks import SnippetChooserBlock
from wagtail.blocks import StructBlock, ListBlock


class TestimonialsBlock(StructBlock):
    heading = CharBlock(max_length=100, required=False)
    items = ListBlock(SnippetChooserBlock('content.Testimonial'))

    class Meta:
        label = 'Блок отзывов'
        template = 'blocks/testimonials.html'

В шаблоне блока данные сниппета доступны напрямую:

{# blocks/testimonials.html #}
<section class="testimonials">
  {% if value.heading %}<h2>{{ value.heading }}</h2>{% endif %}
  <div class="testimonials__grid">
    {% for item in value.items %}
      {% include "snippets/testimonial_card.html" with testimonial=item %}
    {% endfor %}
  </div>
</section>

Сниппет как глобальные настройки

Частый паттерн — сниппет для настроек, которые редактор меняет редко, но которые нужны на всех страницах: контакты, соцсети, SEO-умолчания:

from wagtail.contrib.settings.models import BaseSiteSetting, register_setting


@register_setting
class SiteSettings(BaseSiteSetting):
    phone = models.CharField('Телефон', max_length=30, blank=True)
    email = models.EmailField('Email', blank=True)
    address = models.TextField('Адрес', blank=True)
    vk_url = models.URLField('ВКонтакте', blank=True)
    telegram_url = models.URLField('Telegram', blank=True)
    google_analytics_id = models.CharField('Google Analytics ID', max_length=20, blank=True)

    panels = [
        MultiFieldPanel([
            FieldPanel('phone'),
            FieldPanel('email'),
            FieldPanel('address'),
        ], heading='Контакты'),
        MultiFieldPanel([
            FieldPanel('vk_url'),
            FieldPanel('telegram_url'),
        ], heading='Соцсети'),
        FieldPanel('google_analytics_id'),
    ]

    class Meta:
        verbose_name = 'Настройки сайта'

В шаблонах доступно через тег {% get_settings %}:

{% load wagtailsettings_tags %}
{% get_settings %}
<a href="tel:{{ settings.website.SiteSettings.phone }}">
  {{ settings.website.SiteSettings.phone }}
</a>

API для headless

Если сайт использует Wagtail API, сниппеты нужно явно зарегистрировать в API:

# api.py
from wagtail.api.v2.router import WagtailAPIRouter
from wagtail.api.v2.views import BaseAPIViewSet
from .models import Testimonial

api_router = WagtailAPIRouter('wagtailapi')


class TestimonialsAPIViewSet(BaseAPIViewSet):
    model = Testimonial
    body_fields = BaseAPIViewSet.body_fields + [
        'author_name', 'author_title', 'text', 'rating',
    ]
    listing_default_fields = BaseAPIViewSet.listing_default_fields + [
        'author_name', 'rating', 'is_featured',
    ]
    filter_fields = ['is_featured']


api_router.register_endpoint('testimonials', TestimonialsAPIViewSet)

Запрос вернёт структурированный JSON:

GET /api/v2/testimonials/?is_featured=true&order=-rating

Сроки

Один сниппет с панелями, поиском и фильтрацией — 2–3 часа. Комплект из 5–7 сниппетов для типичного корпоративного сайта (команда, партнёры, отзывы, настройки, меню, баннеры) с настройкой ViewSetGroup и API-доступом — 2–3 дня.