MerixGames

6 grudnia 2016

/ code & tools

Wagtail - system open source do zarządzania treścią (cz. 2)

Filip Stawicki

Wagtail to system open source do zarządzania treścią (CMS) napisanym w Pythonie przy użyciu frameworka Django. Pozwala on na szybkie skonfigurowanie i uruchomienie w pełni funkcjonalnego środowiska dla edytorów. Przy wykorzystaniu mechanizmów znanych z Django Wagtail umożliwia rozbudowanie funkcjonalności aplikacji i dostosowanie jej do konkretnych potrzeb programisty.

W poprzedniej części artykułu poznaliśmy podstawowe funkcje Wagtail CMS i stworzyliśmy prostą aplikację pokazującą część jego możliwości. W tym artykule skupimy się na rozbudowaniu funkcjonalności Wagtail i dodaniu możliwość zarządzania treścią w różnych językach.

Integracja modelstranslation z Wagtail

Na samym początku przy pomocy pip musimy zainstalować modelstranslation:

    $ pip install django-modeltranslation

Szczegółową dokumentację znajdziesz na oficjalnej stronie Django - w moim artykule skupię się jedynie na najważniejszych częściach tej aplikacji

W tym momencie w ustawieniach naszego projektu musimy dodać modeltranslation do INSTALLED_APPS:

    INSTALLED_APPS = (
        …
        'modeltranslation',
    )

Jeśli jeszcze tego nie zrobiłeś, określ w ustawieniach z jakich języków będziesz korzystał:

    LANGUAGES = (
('pl', 'Polski'),
('en', 'English'),
('de', 'Deutsch'),
)

Następnym krokiem jest zarejestrowanie naszych modeli przy użyciu modeltranslation. By to zrobić w aplikacji gallery stwórz plik translation.py z następującym kodem:

    from modeltranslation.translator import register, TranslationOptions

from wagtail.wagtailcore.models import Page

from .models import PhotoPage, GalleryPage


@register(Page)
class PageTranslationOptions(TranslationOptions):
fields = ('title', 'slug')
required_languages = ('pl',)


@register(PhotoPage)
class PhotoPageTranslationOptions(TranslationOptions):
fields = ('header', 'abstract', 'description')
required_languages = ('pl',)


@register(GalleryPage)
class GalleryPageTranslationOptions(TranslationOptions):
fields = ('description',)
required_languages = ('pl',)

Kod ten nie wymaga za dużo tłumaczenia - wykorzystując dekorator @register wybieramy model, jaki chcemy zarejestrować do translacji, by następnie podać listę pól, jakie mają być przetłumaczone. Opcjonalnie możemy także jednoznacznie określić to, jaka wersja językowa ma być uznawana za domyślną. Ze względu na to, że niektóre z pól nie dopuszczają braku zawartości czy pustych ciągów znaków, powinniśmy określić tutaj przynajmniej język - w tym przypadku będzie to język polski.

W tym momencie musimy zaktualizować nasza bazę danych:

    $ python manage.py makemigrations
    $ python manage.py migrate

W plikach migracji widzimy, że modeltranslation utworzył dodatkowe pola, takie jak między innymi title_pl czy title_en. Informację tą wykorzystamy w dalszych etapach naszej pracy.

Stwórzmy dostosowany do naszych potrzeb panel, którego zadaniem będzie zarządzanie tłumaczonymi polami z poziomu admina. Po dodaniu nowego pliku edit_handlers.py do aplikacji gallery możemy umieścić w nim następujące klasy:

    from django.conf import settings

from wagtail.wagtailadmin.edit_handlers import BaseCompositeEditHandler, FieldPanel

class BaseTranslationEditHandler(BaseCompositeEditHandler):
template = 'edit_handlers/translation_panel.html'

class TranslationPanel:
def __init__(self, field_name, heading="", classname=""):
self.heading = heading
self.classname = classname
self.field_name = field_name
self.children = []
self.lang_codes = []

for lang_code in dict(settings.LANGUAGES):
field = FieldPanel('{}_{}'.format(field_name, lang_code))
self.children.append(field)
self.lang_codes.append(lang_code)

def bind_to_model(self, model):
return type('TranslationPanel', (BaseTranslationEditHandler,), {
'model': model,
'children': [child.bind_to_model(model) for child in self.children],
'heading': self.heading,
'classname': self.classname,
'lang_codes': self.lang_codes,
'field_name': self.field_name
})

Komponent ten pozwoli nam na dodawanie do admina tłumaczonych pól w sposób podobny do FieldPanel (np. TranslationPanel(‘title’)).  Dzięki niemu wszystkie języki zadeklarowane w ustawieniach będą automatycznie dostępne w panelu edytora.

BaseTranslationEditHandler został tutaj przeze mnie nadpisany ze względu na to, że chciałem, by wykorzystywał spersonalizowany szablon do renderowania widgetu. Dodajmy ten szablon do katalogu gallery/templates/edit_handlers i nazwijmy go translation_panel.html:

    <h2>
<label>
{{ self.field_name }}
</label>
</h2>

<fieldset>
<legend>{{ self.heading }}</legend>
<div class="translation-tabs">
<ul>
{% for lang_code in self.lang_codes %}
<li>
<a href="#tab-{{ self.field_name }}-{{ forloop.counter }}">{{ lang_code }}</a>
</li>
{% endfor %}
</ul>
{% for child in self.children %}
<div id="tab-{{ self.field_name }}-{{ forloop.counter }}">
{{ child.render_as_field }}
</div>
{% endfor %}
</div>
</fieldset>

By nadpisać domyślny panel używany przez klasę Page, musimy ją rozszerzyć. Dodaj następujący kod do gallery/models.py:

    class TranslatedPage(Page):
        content_panels = [
            TranslationPanel('title'),
        ]

        promote_panels = [
            TranslationPanel('slug')
        ]
  
        class Meta:
            abstract = True

Powinniśmy także zmienić nasze modele PhotoPage i GalleryPage:

    from .edit_handlers import TranslationPanel

        …

    class PhotoPage(TranslatedPage):
        ...

        content_panels = TranslatedPage.content_panels + [
            TranslationPanel('header'),
            FieldPanel('date'),
            ImageChooserPanel('image'),
            TranslationPanel('abstract'),
            TranslationPanel('description'),
        ]


    class GalleryPage(TranslatedPage):
        ...

        content_panels = TranslatedPage.content_panels + [
            TranslationPanel('description')
        ]

Jak sami widzicie, jedynymi różnicami są klasa bazowaj oraz panele przetłumaczonych pól.

Na ten moment funkcjonalność działa dobrze i możemy zobaczyć jak zmienił się panel administracyjny. Zamiast jednego pola możemy edytować jego różne wersje językowe. Jednakże zarządzanie większą liczbą języków na bardziej zaawansowanych stronach szybko stanie się uciążliwe. Aby interfejs był bardziej przyjazny dla redaktorów musimy użyć zakładek jQuery UI.

Rozbudowanie widgetu przy pomocy jQuery i jQuery UI?

jQuery i jQuery UI są już zawarte na stronach admina Wagtail, nie ma więc potrzeby ich importować. Stwórzmy nowy szablon w katalogu <project_name>/templates/wagtailadmin, który nazwiemy base.html.

    {% extends "wagtailadmin/base.html" %}

{% block extra_js %}
{{ block.super }}
<script type="text/javascript">
$(function(){
$('.translation-tabs').tabs();
});
</script>
{% endblock extra_js %}

W podobny sposób możemy dodać spersonalizowany CSS do panelu admina - wystarczy, że nadpiszemy blok extra_cssi dodamy tam nasze pliki.

Z punktu widzenia edytora efekt końcowy powinien wyglądać następująco:

Merixstudio - dodawanie CSS do panelu admina

Na sam koniec musimy dać użytkownikom możliwość przeglądanie różnych wersji językowych naszej aplikacji. By to zrobić musimy nieznacznie zmienić nasz główny plik urls.py:

    from django.conf.urls.i18n import i18n_patterns

        …

    urlpatterns = [
        url(r'^django-admin/', include(admin.site.urls)),

        url(r'^admin/', include(wagtailadmin_urls)),
        url(r'^documents/', include(wagtaildocs_urls)),

        url(r'^search/$', search_views.search, name='search'),
    ]

    urlpatterns += i18n_patterns(
        url(r'', include(wagtail_urls)),  # move this line from urlpatterns list
    )

Teraz w pliku konfiguracyjnym dodajmy middleware odpowiadający za serwowanie odpowiedniej wersji językowej strony:

    MIDDLEWARE_CLASSES = (
        …
        'django.middleware.locale.LocaleMiddleware',
    )

Konkretne wersje językowe strony są teraz dostępne pod adresami:

  • http://127.0.0.1/en/gallery dla wersji angielskiej;
  • http://127.0.0.1/pl/gallery dla wersji polskiej.

Alternatywne narzędzia

Django CMS może być dobrym wyborem dla osób znających Wordpressa. Posiada on wygodny interfejs, który pozwala edytorom na zmianę treści podczas przeglądania renderowanej strony, dzięki czemu mogą oni natychmiast zobaczyć wprowadzane na żywo zmiany. Django CMS jest wyposażony we wbudowany moduł do zarządzania wielojęzycznymi witrynami. Wydaje się on jednakże dość powolny i przeznaczony do obsługi dużych stron internetowych, nie zaś tak, prostego bloga, jak ten, który stworzyliśmy w ramach tego artykułu.

Innym alternatywnym narzędziem, które jest mniej popularne niż Django CMS, jest Mezzanine. Pozwala on edytorom na zarządzanie treścią nie tylko w panelu administratora, ale także “na żywo” w podglądzie strony. Minusem tutaj jest jednak to, że domyślny interfejs administracyjny Mezzanine jest jedynie niewiele bardziej rozbudowany niż ten w Django.

Czego się nauczyliśmy na temat Wagtail?

W drugiej części mojego poradnika skupiłem się na poszerzeniu funkcjonalności Wagtail poprzez stworzenie wielojęzykowej aplikacji. Wykorzystaliśmy więc dodatkowe moduły do Django i zintegrowaliśmy je bez większych problemów z Watgailem. Możliwość łatwego rozbudowywania i modyfikacji Wagtaila jest bez wątpienia jedną z jego największych zalet. Między innymi dzięki temu jest on świetnym narzędziem do tworzenia pełnoprawnych aplikacji internetowych, które są łatwe w obsłudze zarówno dla użytkowników końcowych, jak i edytorów.

Myślisz o realizacji projektu?

Skontaktuj się z nami. Przygotujemy wycenę, opowiemy o szczegółach i procesie wdrożenia.

Napisz do nas

Strona używa plików cookies. Wyrażasz zgodę na używanie cookies, zgodnie z aktualnymi ustawieniami przeglądarki.