Розробка кастомних 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 дні.