Narzędzia użytkownika

Narzędzia witryny


pl:python:views

Różnice

Różnice między wybraną wersją a wersją aktualną.

Odnośnik do tego porównania

Poprzednia rewizja po obu stronachPoprzednia wersja
Nowa wersja
Poprzednia wersja
pl:python:views [2023/12/07 09:38] – [DateDetailView] sindappl:python:views [2023/12/07 19:36] (aktualna) – [ProcessFormView] sindap
Linia 719: Linia 719:
 W szablonie HTML możemy używać specjalnych zmiennych dostarczanych przez ten widok, takich jak ''object'', aby uzyskać dostęp do szczegółów konkretnego obiektu opublikowanego w danym dniu. W szablonie HTML możemy używać specjalnych zmiennych dostarczanych przez ten widok, takich jak ''object'', aby uzyskać dostęp do szczegółów konkretnego obiektu opublikowanego w danym dniu.
 ====== Class-based views mixins ====== ====== Class-based views mixins ======
 +
 +Klasy ''Class-based views mixins'' w Django są używane do dostarczania funkcjonalności, która może być współdzielona między różnymi widokami opartymi o klasy. Są to specjalne klasy zawierające określone metody, które można dołączyć do innych widoków klasowych poprzez dziedziczenie.
 +
 +Najczęściej klasy ''mixins'' są używane do:
 +
 +1. **Współdzielenia kodu:**
 +  * Klasy ''mixins'' pozwalają na współdzielenie kodu między różnymi widokami, co eliminuje potrzebę duplikacji kodu. Dzięki temu można unikać redundancji i utrzymywać bardziej przejrzysty i łatwy do zarządzania kod.
 +
 +2. **Dodawania funkcjonalności:**
 +  * Klasy ''mixins'' dostarczają gotowe funkcje i metody, które mogą być używane w różnych kontekstach. Na przykład, ''mixin'' może dostarczać funkcjonalność do obsługi formularzy, paginacji, autoryzacji itp.
 +
 +3. **Rozszerzania funkcjonalności widoków:**
 +  * ''Mixins'' pozwalają na elastyczne rozszerzanie funkcjonalności widoków klasowych. Dzięki nim można dostosować zachowanie widoków, dodając lub modyfikując pewne aspekty bez konieczności zmiany oryginalnego kodu widoku.
 +
 +Przykład użycia klasy ''mixin'' w Django może wyglądać tak:
 +
 +<code python>
 +from django.contrib.auth.mixins import LoginRequiredMixin
 +from django.views.generic import ListView
 +from .models import YourModel
 +
 +class YourModelListView(LoginRequiredMixin, ListView):
 +    model = YourModel
 +    template_name = 'your_model_list.html'
 +    context_object_name = 'object_list'
 +    paginate_by = 10
 +</code>
 +
 +W tym przykładzie ''LoginRequiredMixin'' jest klasą ''mixin'' dostarczaną przez Django, która wymusza wymaganie logowania użytkownika przed dostępem do widoku. Ta klasa ''mixin'' została dodana do widoku ''YourModelListView'', aby zapewnić wymaganie logowania przed przeglądaniem listy obiektów modelu.
  
 ===== Simple mixins ===== ===== Simple mixins =====
  
 ==== ContextMixin ==== ==== ContextMixin ====
 +
 +''ContextMixin'' w Django jest klasą ''mixin'', która dostarcza mechanizmy do manipulowania kontekstem widoku. Najczęściej stosuje się ją w celu dodawania dodatkowych danych do kontekstu renderowania strony. Głównym celem ''ContextMixin'' jest umożliwienie widokom klasowym dostarczanie dodatkowych informacji, które mogą być używane w szablonach HTML.
 +
 +Poniżej przedstawiam kilka przykładów zastosowań ''ContextMixin'':
 +
 +1. **Dodawanie dodatkowych danych do kontekstu:**
 +  * ''ContextMixin'' pozwala na dodawanie dodatkowych danych do kontekstu, co umożliwia przekazywanie ich do szablonów i wykorzystywanie w renderowaniu strony.
 +
 +<code python>
 +from django.views.generic import TemplateView
 +from django.contrib.auth.models import User
 +
 +class MyContextView(ContextMixin, TemplateView):
 +    template_name = 'my_template.html'
 +
 +    def get_context_data(self, **kwargs):
 +        context = super().get_context_data(**kwargs)
 +        context['additional_data'] = 'Some additional data'
 +        context['users'] = User.objects.all()
 +        return context
 +</code>
 +
 +W tym przykładzie ''MyContextView'' korzysta z ''ContextMixin'' do dodania danych (''additional_data'' i ''users'') do kontekstu. Te dane mogą być używane w szablonie HTML.
 +
 +2. **Przekazywanie dynamicznych danych do kontekstu:**
 +  * Można używać ''ContextMixin'' do przekazywania dynamicznie generowanych danych do kontekstu w zależności od logiki widoku.
 +
 +<code python>
 +from django.views.generic import DetailView
 +from .models import Article
 +
 +class ArticleDetailView(ContextMixin, DetailView):
 +    model = Article
 +    template_name = 'article_detail.html'
 +
 +    def get_context_data(self, **kwargs):
 +        context = super().get_context_data(**kwargs)
 +        context['related_articles'] = article.objects.filter(category=self.object.category).exclude(id=self.object.id)
 +        return context
 +</code>
 +
 +W tym przykładzie ''ArticleDetailView'' używa ''ContextMixin'' do dodania danych o powiązanych artykułach do kontekstu na podstawie kategorii bieżącego artykułu.
 +
 +3. **Współdzielenie danych między różnymi widokami:**
 +  * ''ContextMixin'' umożliwia współdzielenie danych między różnymi widokami, co jest szczególnie przydatne, gdy kilka widoków korzysta z tych samych danych w kontekście.
 +
 +<code python>
 +from django.views.generic import ListView
 +from .models import Category
 +
 +class CategoryListView(ContextMixin, ListView):
 +    model = Category
 +    template_name = 'category_list.html'
 +
 +    def get_context_data(self, **kwargs):
 +        context = super().get_context_data(**kwargs)
 +        context['popular_categories'] = Category.objects.filter(popular=True)
 +        return context
 +</code>
 +
 +Tutaj ''CategoryListView'' korzysta z ''ContextMixin'' do dodania danych o popularnych kategoriach do kontekstu, które mogą być używane w szablonie HTML.
 +
 +Dzięki ''ContextMixin'' programiści mają elastyczność w dostarczaniu danych do kontekstu widoku, co ułatwia zarządzanie danymi i ich wykorzystywanie w szablonach.
  
 ==== TemplateResponseMixin ==== ==== TemplateResponseMixin ====
 +
 +''TemplateResponseMixin''` w Django jest klasą ''mixin''", która dostarcza funkcjonalności związane z renderowaniem szablonów i odpowiedzi na podstawie tych szablonów. Jest często stosowana w widokach klasowych do obsługi renderowania i zwracania odpowiedzi opartej na szablonie. Poniżej przedstawiam najczęstsze zastosowania ''TemplateResponseMixin'':
 +
 +1. **Renderowanie i zwracanie odpowiedzi opartej na szablonie:**
 +  * ''TemplateResponseMixin'' umożliwia widokom klasowym renderowanie szablonów i zwracanie odpowiedzi HTTP opartej na tych szablonach.
 +
 +<code python>
 +from django.views.generic import TemplateView
 +from django.contrib.auth.mixins import LoginRequiredMixin
 +
 +class MyTemplateView(LoginRequiredMixin, TemplateResponseMixin, TemplateView):
 +    template_name = 'my_template.html'
 +</code>
 +
 +W tym przykładzie ''MyTemplateView'' korzysta z ''TemplateResponseMixin'' do renderowania szablonu ''my_template.html'' i zwrócenia odpowiedzi opartej na tym szablonie. ''LoginRequiredMixin'' jest używane jako dodatkowa klasa ''mixin'' do wymuszenia wymaganego logowania użytkownika przed dostępem do widoku.
 +
 +2. **Przekazywanie danych do szablonu:**
 +  * ''TemplateResponseMixin'' pozwala na przekazywanie danych do szablonu za pomocą metody ''get_context_data()''. Dane te mogą być następnie używane do renderowania dynamicznych treści w szablonie.
 +
 +<code python>
 +from django.views.generic import TemplateView
 +
 +class MyDataView(TemplateResponseMixin, TemplateView):
 +    template_name = 'my_data_template.html'
 +
 +    def get_context_data(self, **kwargs):
 +        context = super().get_context_data(**kwargs)
 +        context['custom_data'] = 'Some custom data'
 +        return context
 +</code>
 +
 +W tym przypadku ''MyDataView'' używa ''TemplateResponseMixin'' do przekazania danych (np. ''custom_data'') do szablonu ''my_data_template.html''.
 +
 +3. **Obsługa różnych rodzajów odpowiedzi:**
 +  * ''TemplateResponseMixin'' umożliwia obsługę różnych rodzajów odpowiedzi, takich jak HTML, JSON itp. W zależności od potrzeb, może dostarczać różne odpowiedzi na podstawie tego, jak jest używane.
 +
 +<code python>
 +    from django.views.generic import TemplateView
 +    from django.http import JsonResponse
 +
 +    class MyDataView(TemplateResponseMixin, TemplateView):
 +        template_name = 'my_data_template.html'
 +
 +        def render_to_response(self, context, **response_kwargs):
 +            if self.request.is_ajax():
 +                # Jeśli to jest żądanie AJAX, zwróć odpowiedź JSON
 +                return JsonResponse({'message': 'Ajax response'})
 +            else:
 +                # W przeciwnym razie zwróć standardową odpowiedź HTML
 +                return super().render_to_response(context, **response_kwargs)
 +</code>
 +
 +Tutaj ''MyDataView'' sprawdza, czy żądanie jest żądaniem AJAX, a następnie zwraca odpowiednią odpowiedź: JSON w przypadku żądania AJAX i standardową odpowiedź HTML w przeciwnym razie.
 +
 +''TemplateResponseMixin'' ułatwia obsługę renderowania szablonów i zarządzanie odpowiedziami w widokach klasowych w sposób bardziej zorganizowany i elastyczny.
  
 ===== Single object mixins ===== ===== Single object mixins =====
  
 ==== SingleObjectMixin ==== ==== SingleObjectMixin ====
 +
 +''SingleObjectMixin'' to klasa widoku oparta na klasach (CBV) w Django. Jest często używana w przypadku, gdy chcesz pracować z pojedynczym obiektem modelu w widoku. Oto kilka sytuacji, w których ''SingleObjectMixin'' jest często stosowany:
 +
 +1. **Widok szczegółowy (DetailView):**
 +  * ''SingleObjectMixin'' jest szeroko używany w widokach szczegółowych (''DetailView''), gdzie chcesz wyświetlić szczegółowe informacje o jednym obiekcie modelu.
 +
 +2. **Edycja pojedynczego obiektu (UpdateView):**
 +  * Jeśli chcesz utworzyć widok do edycji pojedynczego obiektu modelu, możesz użyć ''SingleObjectMixin'' w połączeniu z ''UpdateView''.
 +
 +3. **Usunięcie pojedynczego obiektu (DeleteView):**
 +  * Podobnie jak w przypadku edycji, ''SingleObjectMixin'' może być stosowany w widoku usuwania (`DeleteView`), gdzie chcesz umożliwić użytkownikowi usunięcie jednego obiektu.
 +
 +4. **Własne widoki oparte na jednym obiekcie:**
 +  * Jeśli potrzebujesz dostosować widok do specyficznych potrzeb, w których pracujesz z pojedynczym obiektem, ale nie pasuje to do standardowych widoków, możesz skorzystać z ''SingleObjectMixin'' do zbudowania własnego widoku.
 +
 +Przykład użycia ''SingleObjectMixin'' w widoku szczegółowym (''DetailView''):
 +
 +<code python>
 +from django.views.generic.detail import SingleObjectMixin
 +from django.shortcuts import render
 +from .models import YourModel
 +
 +class YourDetailView(SingleObjectMixin):
 +    model = YourModel
 +    template_name = 'your_template.html'
 +
 +    def get(self, request, *args, **kwargs):
 +        # Pobierz pojedynczy obiekt modelu
 +        self.object = self.get_object(queryset=YourModel.objects.all())
 +        return render(request, self.template_name, {'object': self.object})
 +</code>
 +
 +W tym przykładzie ''YourDetailView'' korzysta z ''SingleObjectMixin'' do pobrania pojedynczego obiektu modelu i przekazuje go do szablonu.
 +
 +Można założyć, że widok oparty na ''SingleObjectMixin'' w klasach bazowych (CBV) oferuje możliwość pracy na pojedynczym obiekcie w podobny sposób, jak w przypadku funkcji opartych o funkcje (FBV). ''SingleObjectMixin'' dostarcza mechanizmów do obsługi operacji na jednym obiekcie modelu, takich jak pobieranie, edycja czy usuwanie.
 +
 +Podobieństwa między widokiem ''SingleObjectMixin'' a widokiem FBV obejmują:
 +
 +1. **Pobieranie pojedynczego obiektu:**
 +  * ''get_object()'' w ''SingleObjectMixin'' odpowiada za pobranie pojedynczego obiektu modelu na podstawie przekazanych parametrów URL.
 +
 +2. **Przekazywanie obiektu do szablonu:**
 +  * Po pobraniu obiektu, można przekazać go do szablonu, podobnie jak w przypadku widoku FBV.
 +
 +3. **Dodatkowe operacje na obiekcie:**
 +  * Możesz dostosować widok, aby wykonywał dodatkowe operacje na pobranym obiekcie przed przekazaniem go do szablonu.
 +
 +Przykładowo, poniżej znajduje się kod widoku ''DetailView'' z użyciem ''SingleObjectMixin'':
 +
 +<code python>
 +from django.views.generic.detail import SingleObjectMixin
 +from django.shortcuts import render
 +from .models import YourModel
 +
 +class YourDetailView(SingleObjectMixin):
 +    model = YourModel
 +    template_name = 'your_template.html'
 +
 +    def get(self, request, *args, **kwargs):
 +        # Pobierz pojedynczy obiekt modelu
 +        self.object = self.get_object(queryset=YourModel.objects.all())
 +        
 +        # Dodatkowe operacje na obiekcie (opcjonalne)
 +        # ...
 +
 +        return render(request, self.template_name, {'object': self.object})
 +</code>
 +
 +W kodzie powyżej, ''YourDetailView'' działa podobnie do widoku FBV, gdzie można dostosować operacje na pobranym obiekcie przed przekazaniem go do szablonu.
  
 ==== SingleObjectTemplateResponseMixin ==== ==== SingleObjectTemplateResponseMixin ====
Linia 736: Linia 952:
 ==== MultipleObjectMixin ==== ==== MultipleObjectMixin ====
  
 +''MultipleObjectMixin'' w Django jest klasą, która dostarcza mechanizmów do obsługi widoków, które operują na wielu obiektach modelu. Najczęstszym zastosowaniem ''MultipleObjectMixin'' jest w widokach listy (`ListView`), które wyświetlają listę obiektów modelu.
 +
 +Główne zastosowania ''MultipleObjectMixin'' obejmują:
 +
 +1. **Wyświetlanie listy obiektów:**
 +  * Najczęstszym zastosowaniem ''MultipleObjectMixin'' jest w widokach listy (''ListView''), które wyświetlają listę obiektów modelu. W takim przypadku, ''get_queryset()'' jest używane do pobrania zestawu danych.
 +
 +2. **Filtrowanie i sortowanie listy:**
 +  * ''MultipleObjectMixin'' umożliwia filtrowanie i sortowanie listy obiektów na podstawie określonych kryteriów. Możesz dostosować ''get_queryset()'' w celu zastosowania odpowiednich filtrów i sortowań.
 +
 +3. **Paginacja wyników:**
 +  * W przypadku, gdy lista obiektów jest duża, ''MultipleObjectMixin'' oferuje wbudowaną obsługę paginacji, dzięki której wyniki mogą być podzielone na strony.
 +
 +Przykład użycia ''MultipleObjectMixin'' w widoku listy (''ListView''):
 +
 +<code python>
 +from django.views.generic import ListView
 +from .models import YourModel
 +
 +class YourListView(MultipleObjectMixin, ListView):
 +    model = YourModel
 +    template_name = 'your_template.html'
 +    context_object_name = 'object_list'
 +    paginate_by = 10  # liczba obiektów na stronę
 +
 +    def get_queryset(self):
 +        # Dodatkowe operacje na zestawie danych (opcjonalne)
 +        # ...
 +        
 +        return YourModel.objects.all()
 +</code>
 +
 +W tym przykładzie ''YourListView'' dziedziczy po ''ListView'' i korzysta z `MultipleObjectMixin`. ''get_queryset()'' jest używane do dostosowania zestawu danych, a lista obiektów jest przekazywana do szablonu pod nazwą ''object_list''. Paginacja jest również aktywowana, a liczba obiektów na stronę jest ustawiona na 10.
 +
 +Można przyjąć, że klasę ''SingleObjectMixin'' najczęściej stosuje się w połączeniu z klasami widoków, które obsługują pojedyncze obiekty, takimi jak ''DetailView'', ''UpdateView'', ''DeleteView''. Natomiast klasę ''MultipleObjectMixin'' używa się z klasami, które obsługują listy obiektów, takimi jak ''ListView''.
 +
 +Przykładowo:
 +
 +1. **SingleObjectMixin:**
 +  * ''DetailView'': Wyświetla szczegóły pojedynczego obiektu.
 +  * ''UpdateView'': Aktualizuje pojedynczy obiekt.
 +  * ''DeleteView'': Usuwa pojedynczy obiekt.
 +
 +Przykład z ''DetailView'':
 +
 +<code python>
 +from django.views.generic import DetailView
 +from django.views.generic.detail import SingleObjectMixin
 +from .models import YourModel
 +
 +class YourDetailView(SingleObjectMixin, DetailView):
 +    model = YourModel
 +    template_name = 'your_template.html'
 +    context_object_name = 'object'
 +</code>
 +
 +2. **MultipleObjectMixin:**
 +  * ''ListView'': Wyświetla listę obiektów.
 +  * Inne widoki, które operują na listach obiektów takie jak:''DateListView'', ''ArchiveIndexView'', ''YearArchiveView'', ''MonthArchiveView'', ''WeekArchiveView'', ''DayArchiveView'', ''TodayArchiveView''
 +
 +Przykład z ''ListView'':
 +
 +<code python>
 +from django.views.generic import ListView
 +from django.views.generic.list import MultipleObjectMixin
 +from .models import YourModel
 +
 +class YourListView(MultipleObjectMixin, ListView):
 +    model = YourModel
 +    template_name = 'your_template.html'
 +    context_object_name = 'object_list'
 +    paginate_by = 10
 +</code>
 +
 +Stosowanie odpowiednich ''mixinów'' w zależności od rodzaju widoku pozwala na łatwą i spójną obsługę różnych scenariuszy w aplikacji Django.
 ==== MultipleObjectTemplateResponseMixin ==== ==== MultipleObjectTemplateResponseMixin ====
  
Linia 742: Linia 1033:
 ==== FormMixin ==== ==== FormMixin ====
  
 +''FormMixin'' w Django jest często stosowany do obsługi formularzy w klasach widoków. Jest używany w połączeniu z klasami widoków takimi jak ''CreateView'' i ''UpdateView'', które obsługują tworzenie nowych obiektów i aktualizację istniejących obiektów.
 +
 +''FormMixin'' dostarcza funkcjonalności związanej z obsługą formularzy, takie jak walidacja formularza, zapisywanie formularza, przekazywanie błędów walidacji do kontekstu szablonu itp.
 +
 +Poniżej znajduje się przykład użycia ''FormMixin'' w połączeniu z klasą widoku ''CreateView'', która obsługuje tworzenie nowego obiektu przy użyciu formularza:
 +
 +<code python>
 +from django.views.generic.edit import CreateView
 +from django.views.generic.edit import FormMixin
 +from .models import YourModel
 +from .forms import YourModelForm
 +
 +class YourCreateView(FormMixin, CreateView):
 +    model = YourModel
 +    form_class = YourModelForm
 +    template_name = 'your_template.html'
 +    success_url = '/success/'
 +
 +    def form_valid(self, form):
 +        # Wywołuje się, gdy formularz jest poprawny.
 +        # Tutaj możesz dodać dodatkową logikę przed zapisaniem formularza.
 +        return super().form_valid(form)
 +</code>
 +
 +W tym przypadku ''FormMixin'' dostarcza metodę ''form_valid'', która jest wywoływana, gdy formularz jest poprawny. Możesz w niej umieścić niestandardową logikę przed zapisaniem formularza.
 +
 +Podsumowując, ''FormMixin'' jest używany w klasach widoków do obsługi formularzy i dostarcza szereg funkcji ułatwiających pracę z nimi.
 ==== ModelFormMixin ==== ==== ModelFormMixin ====
  
 +W Django, klasa ''ModelFormMixin'' jest używana w połączeniu z widokami, które obsługują formularze oparte na modelu. Ten mixin dostarcza funkcjonalności związanej z obsługą formularzy w kontekście operacji na modelu. Najczęściej stosuje się go w połączeniu z widokami takimi jak ''CreateView'' i ''UpdateView'', które są odpowiedzialne za tworzenie i aktualizację obiektów modelu.
 +
 +Oto przykład użycia ''ModelFormMixin'' w połączeniu z ''CreateView'':
 +
 +<code python>
 +from django.views.generic.edit import CreateView
 +from django.urls import reverse_lazy
 +from .models import YourModel
 +from .forms import YourModelForm  # Załóżmy, że to jest formularz oparty na modelu
 +
 +class YourCreateView(ModelFormMixin, CreateView):
 +    model = YourModel
 +    form_class = YourModelForm
 +    template_name = 'your_template.html'
 +    success_url = reverse_lazy('your-success-url')
 +
 +    def form_valid(self, form):
 +        # Dodatkowe działania po poprawnej walidacji formularza
 +        return super().form_valid(form)
 +</code>
 +
 +W powyższym przykładzie ''YourCreateView'' jest widokiem, który obsługuje tworzenie nowego obiektu modelu za pomocą formularza (''YourModelForm''). ''ModelFormMixin'' dostarcza funkcji związanych z obsługą formularza i jego zapisywaniem w kontekście operacji na modelu.
 +
 +Podobnie można użyć ''ModelFormMixin'' w połączeniu z ''UpdateView'' do aktualizacji istniejących obiektów modelu. W zależności od przypadku użycia, ''ModelFormMixin'' pomaga w obszarze zapisywania, wyświetlania formularza, walidacji i innych zadań związanych z formularzem na podstawie modelu.
 ==== ProcessFormView ==== ==== ProcessFormView ====
 +
 +W Django, klasa ''ProcessFormView'' to klasa bazowa, która dostarcza funkcjonalności związane z przetwarzaniem formularza w widokach opartych na klasie. Jest to często stosowane wewnątrz innych widoków, takich jak ''FormView'', ''CreateView'', ''UpdateView'', itp., które obsługują formularze.
 +
 +''ProcessFormView'' jest odpowiedzialna za obsługę procesu przetwarzania formularza. W kontekście innych widoków, te zadania są zazwyczaj realizowane automatycznie, a deweloperzy rzadko korzystają bezpośrednio z ''ProcessFormView''. Niemniej jednak, dla bardziej zaawansowanych przypadków użycia, deweloperzy mogą dziedziczyć bezpośrednio z tej klasy, aby dostosować zachowanie przetwarzania formularza w widoku.
 +
 +Oto przykład użycia ''ProcessFormView'':
 +
 +<code python>
 +from django.views.generic.edit import ProcessFormView
 +from django.http import HttpResponseRedirect
 +from django.urls import reverse
 +from .forms import YourForm
 +
 +class YourCustomFormView(ProcessFormView):
 +    form_class = YourForm
 +    template_name = 'your_template.html'
 +
 +    def form_valid(self, form):
 +        # Dodatkowe operacje po poprawnej walidacji formularza
 +        # Możesz dostosować to do swoich potrzeb, na przykład zapisywanie dodatkowych danych
 +        return HttpResponseRedirect(reverse('success-url'))
 +</code>
 +
 +W tym przykładzie ''YourCustomFormView'' dziedziczy z ''ProcessFormView'' i definiuje formularz (''YourForm''). Metoda ''form_valid'' jest wywoływana, gdy formularz jest poprawnie zwalidowany. Deweloper może dostosować tę metodę, aby wykonać dodatkowe operacje po poprawnej walidacji formularza.
 +
 +W praktyce, jednak najczęściej korzystasz z bardziej specjalizowanych klas widoków, które korzystają z ''ProcessFormView'' wewnętrznie, takich jak ''FormView'', ''CreateView'', ''UpdateView'', itp.
  
 ==== DeletionMixin ==== ==== DeletionMixin ====
pl/python/views.1701938324.txt.gz · ostatnio zmienione: 2023/12/07 09:38 przez sindap

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki