diff --git a/district/forms.py b/district/forms.py
index f1ec5b1e44c36893f6269e65dba164c7cc92586c..13c0c657e035bc16270f711260e578c2fc3c546a 100644
--- a/district/forms.py
+++ b/district/forms.py
@@ -36,9 +36,16 @@ class JekyllImportForm(WagtailAdminPageForm):
         "jednoduše URL repozitáře "
         "např. 'https://github.com/pirati-web/cb.pirati.cz'",
     )
+    readonly_log = forms.CharField(
+        disabled=True,
+        label="Log z posledního importu",
+        required=False,
+        widget=forms.Textarea,
+    )
 
-    # def __init__(self):
-    #     pass
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.fields["readonly_log"].initial = self.instance.last_import_log
 
     def clean(self):
         cleaned_data = super().clean()
@@ -72,8 +79,8 @@ class JekyllImportForm(WagtailAdminPageForm):
         return cleaned_data
 
     def handle_import(self):
-        # import_message_list =
-        import_jekyll_articles.delay(
+        # import_jekyll_articles.delay(  # TODO
+        import_jekyll_articles(
             article_parent_page_id=self.instance.id,
             collection_id=self.cleaned_data["collection"].id,
             url=self.cleaned_data["jekyll_repo_url"],
@@ -81,9 +88,6 @@ class JekyllImportForm(WagtailAdminPageForm):
             use_git=self.cleaned_data["use_git"],
         )
 
-        # self.instance.import_message_list = import_message_list
-        # return import_message_list
-
     def save(self, commit=True):
         if self.cleaned_data.get("do_import") and not self.cleaned_data["dry_run"]:
             self.handle_import()
diff --git a/district/jekyll_import.py b/district/jekyll_import.py
index d07d94d71faa959fca967d9dc2b9f7510bc10f42..3e742fbf02bb61ea403ffe38a7d81d86e8ae4809 100644
--- a/district/jekyll_import.py
+++ b/district/jekyll_import.py
@@ -7,19 +7,18 @@ import zipfile
 from datetime import date
 from http.client import InvalidURL
 from io import StringIO
-from sys import stdout
 from typing import List
 from urllib.error import HTTPError
 
 import markdown.serializers
 import yaml
-from django.contrib.messages import INFO, SUCCESS, WARNING
 from django.core.files.images import ImageFile
 from django.utils import timezone
 from markdown import Markdown
 from markdown.extensions import Extension
 from markdown.inlinepatterns import InlineProcessor
 from wagtail.contrib.redirects.models import Redirect
+from wagtail.core.models import Page
 from wagtail.core.models.collections import Collection
 from wagtail.core.rich_text import RichText
 from wagtail.images.models import Image
@@ -28,9 +27,8 @@ from yaml.scanner import ScannerError
 logger = logging.getLogger(__name__)
 # from django.utils.dateparse import parse_date TODO enable date check again...
 
-image_params = (
-    {}
-)  # filled on JekyllArticleImported init and used in markdown overwrites
+image_params = {}  # filled on JekyllArticleImporter init and used globally
+
 POSTS_DIR = "_posts"
 
 # ------------------------------- Misc helper functions -------------------------------
@@ -114,13 +112,13 @@ def get_or_create_image(
     file_path = file_path.lstrip("/")
 
     if Image.objects.filter(title=file_path).exists():
-        return Image.objects.filter(title=file_path).first()
+        return Image.objects.filter(title=file_path).first(), ""
     else:
         try:
             file = ImageFile(open(os.path.join(path, file_path), "rb"), name=file_path)
             image = Image(title=file_path, file=file, collection=collection)
             image.save()
-            return image
+            return image, ""
         except FileNotFoundError:
             try:
                 file = ImageFile(
@@ -129,7 +127,7 @@ def get_or_create_image(
                 )
                 image = Image(title=file_path, file=file, collection=collection)
                 image.save()
-                return image
+                return image, ""
             except FileNotFoundError:
                 img_name = file_path.split("/")[-1]
                 img_assets_folder = repo_name.split(".")[0]
@@ -152,20 +150,22 @@ def get_or_create_image(
                         InvalidURL,
                         IsADirectoryError,
                     ):
+                        msg = "Nedohledán obrázek při importu článků"
+                        log_message = "{} - {}\n".format(msg, img_url)
                         logger.warning(
-                            "Nedohledán obrázek při importu článků",
+                            msg,
                             extra={
                                 "file_path": file_path,
                                 "img_name": img_name,
                                 "img_url": img_url,
                             },
                         )
-                        return None
+                        return None, log_message
 
                 file = ImageFile(open(img_path, "rb"), name=img_path)
                 image = Image(title=file_path, file=file, collection=collection)
                 image.save()
-                return image
+                return image, ""
 
 
 def get_path_and_repo_name(url: str, use_git: bool) -> (str, str):
@@ -220,7 +220,7 @@ class ImgProcessor(InlineProcessor):
         el.attrib["format"] = "left"
 
         parsed_image_path = JekyllArticleImporter.get_parsed_file_path(m.group(2))
-        image_obj = get_or_create_image(
+        image_obj, _ = get_or_create_image(
             path=image_params["path"],
             file_path=parsed_image_path,
             collection=image_params["collection"],
@@ -263,13 +263,15 @@ class JekyllArticleImporter:
         url: str,
         dry_run: bool,
         use_git: bool,
+        parent_page_model,
+        page_model,
     ):
-        from district.models import DistrictArticlesPage
+        self.page_model = page_model
 
         # Params
-        self.article_parent_page = DistrictArticlesPage.objects.get(
+        self.article_parent_page = parent_page_model.objects.get(
             id=article_parent_page_id
-        )
+        ).specific  # TODO test if specific should be included or not
         self.collection = Collection.objects.get(id=collection_id)
         self.dry_run = dry_run
         self.use_git = use_git
@@ -288,46 +290,33 @@ class JekyllArticleImporter:
         self.success_counter = 0
         self.exists_counter = 0
         self.skipped_counter = 0
-        # self.image_warning_counter = 0  # TODO nějak vymyslet
 
-        self.message_list = []  # output for django.messages
+        self.page_log = ""  # output saved on page instance
 
         # Filling global var for ImgParser
         image_params["path"] = self.path
         image_params["collection"] = self.collection
         image_params["repo_name"] = self.repo_name
 
-    def create_django_messages(self):
+    def create_summary_log(self):
         """
-        Podle (aktuálních) hodnot counterů přidá do self.message_list
+        Podle (aktuálních) hodnot counterů přidá do self.page_log
         různé zprávy pro uživatele.
         """
+        self.page_log += "==================================\n"
+
         if self.success_counter:
-            base_msg = "Lze importovat" if self.dry_run else "Úspěšně naimportováno"
-            self.message_list.append(
-                {
-                    "level": SUCCESS,
-                    "text": "{} {} článků".format(base_msg, self.success_counter),
-                }
-            )
+            base_msg = "Úspěšně otestováno" if self.dry_run else "Úspěšně naimportováno"
+            self.page_log += "{} {} článků\n".format(base_msg, self.success_counter)
 
         if self.exists_counter:
-            self.message_list.append(
-                {
-                    "level": INFO,
-                    "text": "{} článků s tímto názvem již existuje".format(
-                        self.exists_counter
-                    ),
-                }
-            )
+            self.page_log += "z toho {} již existovalo\n".format(self.exists_counter)
 
         if self.skipped_counter:
-            self.message_list.append(
-                {
-                    "level": WARNING,
-                    "text": "Nelze importovat {} článků".format(self.skipped_counter),
-                }
-            )
+            self.page_log += "NELZE importovat {} článků\n".format(self.skipped_counter)
+
+        self.article_parent_page.last_import_log = self.page_log
+        self.article_parent_page.save()
 
     @staticmethod
     def get_parsed_file_path(path: str):
@@ -382,17 +371,15 @@ class JekyllArticleImporter:
         return meta_dict
 
     def import_post(self, file_path):
-        from district.models import DistrictArticlePage
 
         with open(os.path.join(self.path, file_path), "rt") as f:
             r = re.split(r"^---\s*$", f.read(), maxsplit=3, flags=re.MULTILINE)
         try:
             meta = yaml.safe_load(r[1].replace("\t", ""))
         except (ScannerError, ValueError):
-            logger.warning(
-                "Nelze importovat článek - neparsovatelný YAML",
-                extra={"file_path": file_path},
-            )
+            msg = "Nelze importovat článek - neparsovatelný YAML"
+            logger.warning(msg, extra={"file_path": file_path})
+            self.page_log += "{} - {}\n".format(msg, file_path)
             self.skipped_counter += 1
             return None
 
@@ -405,24 +392,19 @@ class JekyllArticleImporter:
         try:
             title = meta["title"]
         except TypeError:
-            logger.warning(
-                "Nelze importovat článek - nepodařilo se získat title",
-                extra={"article_meta": meta},
-            )
+            msg = "Nelze importovat článek - nepodařilo se získat title"
+            logger.warning(msg, extra={"article_meta": meta})
+            self.page_log += "{} - {}\n".format(msg, meta)
             self.skipped_counter += 1
             return None
 
-        if DistrictArticlePage.objects.filter(title=title).exists():
-            for article in DistrictArticlePage.objects.filter(title=meta["title"]):
-                # if article.date == parse_date(meta["date"].split()[0]):
-                msg = "Článek již existuje: %s" % article
-                stdout.write(msg)
-                # message_list.append({"level": INFO, "text": msg})
-                self.exists_counter += 1
-
-                return None
-
-        article = DistrictArticlePage()
+        try:
+            article = (
+                self.article_parent_page.get_descendants().get(title=title).specific
+            )
+            self.exists_counter += 1
+        except (Page.DoesNotExist, Page.MultipleObjectsReturned):
+            article = self.page_model()
 
         # article.text = html
         article.content = [("text", RichText(html))]
@@ -450,24 +432,29 @@ class JekyllArticleImporter:
         #     article.tags.add(tag)
 
         if meta.get("image", None):
-            article.image = get_or_create_image(
+            article.image, log_message = get_or_create_image(
                 self.path, meta["image"], self.collection, self.repo_name
             )
+            if log_message:
+                self.page_log += log_message
 
         if self.dry_run:
             return article
 
         try:
-            self.article_parent_page.add_child(instance=article)
-            stdout.write("Vytvářím článek: %s" % article)
+            if not article.id:
+                self.article_parent_page.add_child(instance=article)
+            logger.info("Vytvářím článek: %s" % article)
             rev = article.save_revision()
             if meta.get("published", True):
                 rev.publish()
         except Exception as e:
+            msg = "Nelze uložit importovaný článek"
             logger.warning(
-                "Nelze uložit importovaný článek",
+                msg,
                 extra={"article_title": article.title, "exception": e},
             )
+            self.page_log += "{} - {} - {}\n".format(msg, article.title, e)
             self.skipped_counter += 1
             return article
 
@@ -479,6 +466,7 @@ class JekyllArticleImporter:
         Projde adresář článků a pokusí se zprocesovat Markdown do article.
         Vrací list dict pro django messages (klíč levelu, text).
         """
+        logger.info("Import započat")
         for file_name in os.listdir(os.path.join(self.path, POSTS_DIR)):
             # Případ podsložek (typicky po jednotlivých letech)
             if os.path.isdir(os.path.join(self.path, POSTS_DIR, file_name)):
@@ -491,8 +479,8 @@ class JekyllArticleImporter:
                 file_path = os.path.join(POSTS_DIR, file_name)
                 self.process_article(file_name, file_path)
 
-        self.create_django_messages()
-        return self.message_list
+        self.create_summary_log()
+        logger.info("Import dokončen")
 
     def process_article(self, file_name: str, file_path: str):
         match = re.match(r"(\d*)-(\d*)-(\d*)-(.*)\.(.*)", file_name)
@@ -527,8 +515,10 @@ class JekyllArticleImporter:
             else:
                 msg = "Nepodporovaná přípona souboru: %s" % ext
                 logger.warning(msg)
+                self.page_log += "{}\n".format(msg)
                 self.skipped_counter += 1
         else:
             msg = "Přeskočeno: %s" % file_name
             logger.warning(msg)
+            self.page_log += "{}\n".format(msg)
             self.skipped_counter += 1
diff --git a/district/migrations/0049_districtarticlespage_last_import_log.py b/district/migrations/0049_districtarticlespage_last_import_log.py
new file mode 100644
index 0000000000000000000000000000000000000000..8f96040dff96aad294be0806eb10258af056b964
--- /dev/null
+++ b/district/migrations/0049_districtarticlespage_last_import_log.py
@@ -0,0 +1,20 @@
+# Generated by Django 4.0.3 on 2022-04-01 11:30
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("district", "0048_districthomepage_footperson_coord_title_and_more"),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name="districtarticlespage",
+            name="last_import_log",
+            field=models.TextField(
+                blank=True, null=True, verbose_name="Výstup z posledního importu"
+            ),
+        ),
+    ]
diff --git a/district/models.py b/district/models.py
index 8d950e3a2658b9c760f194c16e20e6180a0d9723..0ecb40280ea83038f5d4121a2650d76509748d09 100644
--- a/district/models.py
+++ b/district/models.py
@@ -365,6 +365,9 @@ class DistrictArticlePage(ArticleMixin, SubpageMixin, MetadataPageMixin, Page):
 class DistrictArticlesPage(SubpageMixin, MetadataPageMixin, Page):
     ### FIELDS
 
+    last_import_log = models.TextField(
+        "Výstup z posledního importu", null=True, blank=True
+    )
     max_items = models.IntegerField("Počet článků na stránce", default=12)
 
     ### PANELS
@@ -383,9 +386,14 @@ class DistrictArticlesPage(SubpageMixin, MetadataPageMixin, Page):
                 FieldPanel("dry_run"),
                 FieldPanel("use_git"),
                 FieldPanel("jekyll_repo_url"),
+                FieldPanel("readonly_log"),
                 HelpPanel(
-                    "Import provádějte vždy až po vytvoření stránky aktualit."
-                    "Import proběhne na pozadí a může trvat až několik minut."
+                    "Import provádějte vždy až po vytvoření stránky aktualit. "
+                    'Pro uložení logu je nutné volit možnost "Publikovat", nikoliv'
+                    'pouze "Uložit koncept". '
+                    "Import proběhne na pozadí a může trvat až několik minut. "
+                    "Dejte si po spuštění importu kávu a potom obnovte stránku pro "
+                    "zobrazení výsledku importu."
                 ),
             ],
             "import z Jekyll repozitáře",
@@ -425,6 +433,9 @@ class DistrictArticlesPage(SubpageMixin, MetadataPageMixin, Page):
         ).get_page(request.GET.get("page"))
         return context
 
+    def save(self, clean=True, user=None, log_action=False, **kwargs):
+        super(DistrictArticlesPage, self).save()
+
 
 class DistrictContactPage(SubpageMixin, MetadataPageMixin, Page):
     ### FIELDS
diff --git a/district/tasks.py b/district/tasks.py
index 859d217b20f1da8c3f23adb44f272432c90359c8..e0d9c6cd61bb29b8ecb6f027fd739d596c6c7598 100644
--- a/district/tasks.py
+++ b/district/tasks.py
@@ -15,10 +15,14 @@ def import_jekyll_articles(
     dry_run: bool,
     use_git: bool,
 ):
+    from .models import DistrictArticlePage, DistrictArticlesPage
+
     return JekyllArticleImporter(
         article_parent_page_id=article_parent_page_id,
         collection_id=collection_id,
         url=url,
         dry_run=dry_run,
         use_git=use_git,
+        parent_page_model=DistrictArticlesPage,
+        page_model=DistrictArticlePage,
     ).perform_import()
diff --git a/district/wagtail_hooks.py b/district/wagtail_hooks.py
index 896696bcf9e082fd92e2c7b3e1aded69a78dbe42..ea3324d401ca66f0a0c822b8b60ade28a8417ab8 100644
--- a/district/wagtail_hooks.py
+++ b/district/wagtail_hooks.py
@@ -1,20 +1,3 @@
-from django.contrib.messages import ERROR, SUCCESS, WARNING, add_message
-from wagtail.admin import messages
-from wagtail.core import hooks
-
-from .models import DistrictArticlesPage
-
-
-@hooks.register("after_edit_page")
-@hooks.register("after_edit_page")
-def handle_page_import(request, page):  # def after_create_page(request, page):
-    """Block awesome page deletion and show a message."""
-
-    if request.method == "POST" and page.specific_class in [DistrictArticlesPage]:
-        for message in getattr(page, "import_message_list", []):
-            add_message(request, message["level"], message["text"])
-
-
 # import re
 #
 # from wagtail.core import hooks