diff --git a/district/migrations/0001_initial.py b/district/migrations/0001_initial.py
index 50801c1b402c6f160ea374716bef112ee2a7d677..6984bc22c0faa2ce5dafc0a48a8739ea82a66181 100644
--- a/district/migrations/0001_initial.py
+++ b/district/migrations/0001_initial.py
@@ -1,22 +1,214 @@
-# Generated by Django 3.1.1 on 2020-10-07 06:42
+# Generated by Django 3.1.3 on 2021-01-18 22:54
 
 import django.db.models.deletion
+import django.utils.timezone
+import modelcluster.contrib.taggit
+import modelcluster.fields
 import wagtail.core.blocks
 import wagtail.core.fields
 import wagtailmetadata.models
 from django.db import migrations, models
 
+import shared.models
+
 
 class Migration(migrations.Migration):
 
     initial = True
 
     dependencies = [
-        ("wagtailcore", "0052_pagelogentry"),
+        ("taggit", "0003_taggeditem_add_unique_index"),
         ("wagtailimages", "0022_uploadedimage"),
+        ("shared", "0001_initial"),
+        ("wagtailcore", "0059_apply_collection_ordering"),
     ]
 
     operations = [
+        migrations.CreateModel(
+            name="DistrictArticlePage",
+            fields=[
+                (
+                    "page_ptr",
+                    models.OneToOneField(
+                        auto_created=True,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        parent_link=True,
+                        primary_key=True,
+                        serialize=False,
+                        to="wagtailcore.page",
+                    ),
+                ),
+                (
+                    "perex",
+                    models.CharField(blank=True, max_length=250, verbose_name="perex"),
+                ),
+                (
+                    "text",
+                    wagtail.core.fields.RichTextField(
+                        blank=True, verbose_name="text článku"
+                    ),
+                ),
+                (
+                    "date",
+                    models.DateField(
+                        default=django.utils.timezone.now, verbose_name="datum článku"
+                    ),
+                ),
+                (
+                    "author",
+                    models.CharField(
+                        blank=True, max_length=250, null=True, verbose_name="autor"
+                    ),
+                ),
+                (
+                    "image",
+                    models.ForeignKey(
+                        blank=True,
+                        null=True,
+                        on_delete=django.db.models.deletion.PROTECT,
+                        to="wagtailimages.image",
+                        verbose_name="obrázek",
+                    ),
+                ),
+                (
+                    "search_image",
+                    models.ForeignKey(
+                        blank=True,
+                        null=True,
+                        on_delete=django.db.models.deletion.SET_NULL,
+                        related_name="+",
+                        to="wagtailimages.image",
+                        verbose_name="Search image",
+                    ),
+                ),
+            ],
+            options={
+                "verbose_name": "Aktualita",
+            },
+            bases=(
+                shared.models.SubpageMixin,
+                wagtailmetadata.models.MetadataMixin,
+                "wagtailcore.page",
+                models.Model,
+            ),
+        ),
+        migrations.CreateModel(
+            name="DistrictTagsPage",
+            fields=[
+                (
+                    "page_ptr",
+                    models.OneToOneField(
+                        auto_created=True,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        parent_link=True,
+                        primary_key=True,
+                        serialize=False,
+                        to="wagtailcore.page",
+                    ),
+                ),
+                (
+                    "search_image",
+                    models.ForeignKey(
+                        blank=True,
+                        null=True,
+                        on_delete=django.db.models.deletion.SET_NULL,
+                        related_name="+",
+                        to="wagtailimages.image",
+                        verbose_name="Search image",
+                    ),
+                ),
+            ],
+            options={
+                "verbose_name": "Stránka s tagy",
+            },
+            bases=(
+                shared.models.SubpageMixin,
+                wagtailmetadata.models.MetadataMixin,
+                "wagtailcore.page",
+                models.Model,
+            ),
+        ),
+        migrations.CreateModel(
+            name="DistrictPersonPage",
+            fields=[
+                (
+                    "page_ptr",
+                    models.OneToOneField(
+                        auto_created=True,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        parent_link=True,
+                        primary_key=True,
+                        serialize=False,
+                        to="wagtailcore.page",
+                    ),
+                ),
+                ("perex", models.TextField(blank=True, verbose_name="Perex osoby")),
+                (
+                    "person",
+                    models.ForeignKey(
+                        null=True,
+                        on_delete=django.db.models.deletion.PROTECT,
+                        to="shared.person",
+                    ),
+                ),
+                (
+                    "search_image",
+                    models.ForeignKey(
+                        blank=True,
+                        null=True,
+                        on_delete=django.db.models.deletion.SET_NULL,
+                        related_name="+",
+                        to="wagtailimages.image",
+                        verbose_name="Search image",
+                    ),
+                ),
+            ],
+            options={
+                "verbose_name": "Detail osoby",
+            },
+            bases=(
+                shared.models.SubpageMixin,
+                wagtailmetadata.models.MetadataMixin,
+                "wagtailcore.page",
+                models.Model,
+            ),
+        ),
+        migrations.CreateModel(
+            name="DistrictPeoplePage",
+            fields=[
+                (
+                    "page_ptr",
+                    models.OneToOneField(
+                        auto_created=True,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        parent_link=True,
+                        primary_key=True,
+                        serialize=False,
+                        to="wagtailcore.page",
+                    ),
+                ),
+                (
+                    "search_image",
+                    models.ForeignKey(
+                        blank=True,
+                        null=True,
+                        on_delete=django.db.models.deletion.SET_NULL,
+                        related_name="+",
+                        to="wagtailimages.image",
+                        verbose_name="Search image",
+                    ),
+                ),
+            ],
+            options={
+                "verbose_name": "Lidé",
+            },
+            bases=(
+                shared.models.SubpageMixin,
+                wagtailmetadata.models.MetadataMixin,
+                "wagtailcore.page",
+                models.Model,
+            ),
+        ),
         migrations.CreateModel(
             name="DistrictHomePage",
             fields=[
@@ -54,6 +246,30 @@ class Migration(migrations.Migration):
                     "forum",
                     models.URLField(blank=True, null=True, verbose_name="Fórum URL"),
                 ),
+                (
+                    "contact_email",
+                    models.EmailField(
+                        blank=True, max_length=250, verbose_name="kontaktni email"
+                    ),
+                ),
+                (
+                    "contact_phone",
+                    models.TextField(
+                        blank=True, max_length=250, verbose_name="kontaktni telefon"
+                    ),
+                ),
+                (
+                    "contact_newcomers",
+                    models.URLField(
+                        blank=True, null=True, verbose_name="URL pro zájemce o členství"
+                    ),
+                ),
+                (
+                    "donation_page",
+                    models.URLField(
+                        blank=True, null=True, verbose_name="URL pro příjem darů"
+                    ),
+                ),
                 (
                     "matomo_id",
                     models.IntegerField(
@@ -62,6 +278,39 @@ class Migration(migrations.Migration):
                         verbose_name="Matomo ID pro sledování návštěvnosti",
                     ),
                 ),
+                (
+                    "footperson_coord",
+                    models.ForeignKey(
+                        blank=True,
+                        null=True,
+                        on_delete=django.db.models.deletion.PROTECT,
+                        related_name="footperson_coord",
+                        to="shared.person",
+                        verbose_name="Koordinátor",
+                    ),
+                ),
+                (
+                    "footperson_electman",
+                    models.ForeignKey(
+                        blank=True,
+                        null=True,
+                        on_delete=django.db.models.deletion.PROTECT,
+                        related_name="footperson_electman",
+                        to="shared.person",
+                        verbose_name="Volební manažer",
+                    ),
+                ),
+                (
+                    "footperson_media",
+                    models.ForeignKey(
+                        blank=True,
+                        null=True,
+                        on_delete=django.db.models.deletion.PROTECT,
+                        related_name="footperson_media",
+                        to="shared.person",
+                        verbose_name="Kontakt pro média",
+                    ),
+                ),
                 (
                     "search_image",
                     models.ForeignKey(
@@ -83,4 +332,156 @@ class Migration(migrations.Migration):
                 models.Model,
             ),
         ),
+        migrations.CreateModel(
+            name="DistrictContactPage",
+            fields=[
+                (
+                    "page_ptr",
+                    models.OneToOneField(
+                        auto_created=True,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        parent_link=True,
+                        primary_key=True,
+                        serialize=False,
+                        to="wagtailcore.page",
+                    ),
+                ),
+                (
+                    "contact_people",
+                    wagtail.core.fields.StreamField(
+                        [
+                            (
+                                "item",
+                                wagtail.core.blocks.StructBlock(
+                                    [
+                                        (
+                                            "name",
+                                            wagtail.core.blocks.CharBlock(label="Role"),
+                                        ),
+                                        (
+                                            "person",
+                                            wagtail.core.blocks.PageChooserBlock(
+                                                label="Osoba",
+                                                page_type=[
+                                                    "district.DistrictPersonPage"
+                                                ],
+                                            ),
+                                        ),
+                                    ]
+                                ),
+                            )
+                        ],
+                        blank=True,
+                        verbose_name="Kontakty",
+                    ),
+                ),
+                (
+                    "search_image",
+                    models.ForeignKey(
+                        blank=True,
+                        null=True,
+                        on_delete=django.db.models.deletion.SET_NULL,
+                        related_name="+",
+                        to="wagtailimages.image",
+                        verbose_name="Search image",
+                    ),
+                ),
+            ],
+            options={
+                "verbose_name": "Kontakty",
+            },
+            bases=(
+                shared.models.SubpageMixin,
+                wagtailmetadata.models.MetadataMixin,
+                "wagtailcore.page",
+                models.Model,
+            ),
+        ),
+        migrations.CreateModel(
+            name="DistrictArticleTag",
+            fields=[
+                (
+                    "id",
+                    models.AutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "content_object",
+                    modelcluster.fields.ParentalKey(
+                        on_delete=django.db.models.deletion.CASCADE,
+                        to="district.districtarticlepage",
+                    ),
+                ),
+                (
+                    "tag",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="district_districtarticletag_items",
+                        to="taggit.tag",
+                    ),
+                ),
+            ],
+            options={
+                "abstract": False,
+            },
+        ),
+        migrations.CreateModel(
+            name="DistrictArticlesPage",
+            fields=[
+                (
+                    "page_ptr",
+                    models.OneToOneField(
+                        auto_created=True,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        parent_link=True,
+                        primary_key=True,
+                        serialize=False,
+                        to="wagtailcore.page",
+                    ),
+                ),
+                (
+                    "max_items",
+                    models.IntegerField(
+                        blank=True,
+                        null=True,
+                        verbose_name="Maximalni pocet prvku na strance",
+                    ),
+                ),
+                (
+                    "search_image",
+                    models.ForeignKey(
+                        blank=True,
+                        null=True,
+                        on_delete=django.db.models.deletion.SET_NULL,
+                        related_name="+",
+                        to="wagtailimages.image",
+                        verbose_name="Search image",
+                    ),
+                ),
+            ],
+            options={
+                "verbose_name": "Aktuality",
+            },
+            bases=(
+                shared.models.SubpageMixin,
+                wagtailmetadata.models.MetadataMixin,
+                "wagtailcore.page",
+                models.Model,
+            ),
+        ),
+        migrations.AddField(
+            model_name="districtarticlepage",
+            name="tags",
+            field=modelcluster.contrib.taggit.ClusterTaggableManager(
+                blank=True,
+                help_text="A comma-separated list of tags.",
+                through="district.DistrictArticleTag",
+                to="taggit.Tag",
+                verbose_name="Tags",
+            ),
+        ),
     ]
diff --git a/district/migrations/0002_districtarticles.py b/district/migrations/0002_districtarticles.py
deleted file mode 100644
index 768ba41c1c0e5fb1b548a4557b90cec894aef3c9..0000000000000000000000000000000000000000
--- a/district/migrations/0002_districtarticles.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# Generated by Django 3.1.1 on 2020-10-07 09:57
-
-import django.db.models.deletion
-import wagtailmetadata.models
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ("wagtailcore", "0052_pagelogentry"),
-        ("wagtailimages", "0022_uploadedimage"),
-        ("district", "0001_initial"),
-    ]
-
-    operations = [
-        migrations.CreateModel(
-            name="DistrictArticles",
-            fields=[
-                (
-                    "page_ptr",
-                    models.OneToOneField(
-                        auto_created=True,
-                        on_delete=django.db.models.deletion.CASCADE,
-                        parent_link=True,
-                        primary_key=True,
-                        serialize=False,
-                        to="wagtailcore.page",
-                    ),
-                ),
-                (
-                    "max_items",
-                    models.IntegerField(
-                        blank=True,
-                        null=True,
-                        verbose_name="Maximalni pocet prvku na strance",
-                    ),
-                ),
-                (
-                    "search_image",
-                    models.ForeignKey(
-                        blank=True,
-                        null=True,
-                        on_delete=django.db.models.deletion.SET_NULL,
-                        related_name="+",
-                        to="wagtailimages.image",
-                        verbose_name="Search image",
-                    ),
-                ),
-            ],
-            options={
-                "verbose_name": "Aktuality",
-            },
-            bases=(
-                wagtailmetadata.models.MetadataMixin,
-                "wagtailcore.page",
-                models.Model,
-            ),
-        ),
-    ]
diff --git a/district/migrations/0003_auto_20201007_1410.py b/district/migrations/0003_auto_20201007_1410.py
deleted file mode 100644
index e84ebf7ce1740aec8b818acbca96722ae243f7ad..0000000000000000000000000000000000000000
--- a/district/migrations/0003_auto_20201007_1410.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# Generated by Django 3.1.1 on 2020-10-07 12:10
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ("district", "0002_districtarticles"),
-    ]
-
-    operations = [
-        migrations.AddField(
-            model_name="districthomepage",
-            name="contact_email",
-            field=models.EmailField(
-                blank=True, max_length=250, verbose_name="kontaktni email"
-            ),
-        ),
-        migrations.AddField(
-            model_name="districthomepage",
-            name="contact_newcomers",
-            field=models.URLField(
-                blank=True, null=True, verbose_name="URL pro zájemce o členství"
-            ),
-        ),
-    ]
diff --git a/district/migrations/0004_districthomepage_donation_page.py b/district/migrations/0004_districthomepage_donation_page.py
deleted file mode 100644
index cc607d744b899e53a5c62243b3bcbc52b332458c..0000000000000000000000000000000000000000
--- a/district/migrations/0004_districthomepage_donation_page.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# Generated by Django 3.1.1 on 2020-10-07 12:22
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ("district", "0003_auto_20201007_1410"),
-    ]
-
-    operations = [
-        migrations.AddField(
-            model_name="districthomepage",
-            name="donation_page",
-            field=models.URLField(
-                blank=True, null=True, verbose_name="URL pro příjem darů"
-            ),
-        ),
-    ]
diff --git a/district/migrations/0005_districthomepage_footperson_contact.py b/district/migrations/0005_districthomepage_footperson_contact.py
deleted file mode 100644
index 1df05e2915aadfc23cb384fb93c9a566bd0d6a86..0000000000000000000000000000000000000000
--- a/district/migrations/0005_districthomepage_footperson_contact.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# Generated by Django 3.1.1 on 2020-10-14 10:09
-
-import django.db.models.deletion
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ("shared", "0008_personpage_search_image"),
-        ("district", "0004_districthomepage_donation_page"),
-    ]
-
-    operations = [
-        migrations.AddField(
-            model_name="districthomepage",
-            name="footperson_contact",
-            field=models.ForeignKey(
-                blank=True,
-                null=True,
-                on_delete=django.db.models.deletion.PROTECT,
-                to="shared.personpage",
-                verbose_name="Kontaktní osoba",
-            ),
-        ),
-    ]
diff --git a/district/migrations/0006_auto_20201014_1230.py b/district/migrations/0006_auto_20201014_1230.py
deleted file mode 100644
index a459cbfa8ac9fbc7482b9b13ad3efedbf65f3d2f..0000000000000000000000000000000000000000
--- a/district/migrations/0006_auto_20201014_1230.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Generated by Django 3.1.1 on 2020-10-14 10:30
-
-from django.db import migrations
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ("district", "0005_districthomepage_footperson_contact"),
-    ]
-
-    operations = [
-        migrations.RenameField(
-            model_name="districthomepage",
-            old_name="footperson_contact",
-            new_name="footperson_coord",
-        ),
-    ]
diff --git a/district/migrations/0007_auto_20201014_1232.py b/district/migrations/0007_auto_20201014_1232.py
deleted file mode 100644
index 033cfb8061b3f31815c24103622aebde42d27240..0000000000000000000000000000000000000000
--- a/district/migrations/0007_auto_20201014_1232.py
+++ /dev/null
@@ -1,51 +0,0 @@
-# Generated by Django 3.1.1 on 2020-10-14 10:32
-
-import django.db.models.deletion
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ("shared", "0008_personpage_search_image"),
-        ("district", "0006_auto_20201014_1230"),
-    ]
-
-    operations = [
-        migrations.AddField(
-            model_name="districthomepage",
-            name="footperson_electman",
-            field=models.ForeignKey(
-                blank=True,
-                null=True,
-                on_delete=django.db.models.deletion.PROTECT,
-                related_name="footperson_electman",
-                to="shared.personpage",
-                verbose_name="Volební manažer",
-            ),
-        ),
-        migrations.AddField(
-            model_name="districthomepage",
-            name="footperson_media",
-            field=models.ForeignKey(
-                blank=True,
-                null=True,
-                on_delete=django.db.models.deletion.PROTECT,
-                related_name="footperson_media",
-                to="shared.personpage",
-                verbose_name="Kontakt pro média",
-            ),
-        ),
-        migrations.AlterField(
-            model_name="districthomepage",
-            name="footperson_coord",
-            field=models.ForeignKey(
-                blank=True,
-                null=True,
-                on_delete=django.db.models.deletion.PROTECT,
-                related_name="footperson_coord",
-                to="shared.personpage",
-                verbose_name="Koordinátor",
-            ),
-        ),
-    ]
diff --git a/district/migrations/0008_districtcontact.py b/district/migrations/0008_districtcontact.py
deleted file mode 100644
index f4adec5671a5b936d46035541b1857288bd0dab0..0000000000000000000000000000000000000000
--- a/district/migrations/0008_districtcontact.py
+++ /dev/null
@@ -1,84 +0,0 @@
-# Generated by Django 3.1.1 on 2020-10-14 11:23
-
-import django.db.models.deletion
-import wagtail.core.blocks
-import wagtail.core.fields
-import wagtailmetadata.models
-from django.db import migrations, models
-
-import district.models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ("wagtailcore", "0052_pagelogentry"),
-        ("wagtailimages", "0022_uploadedimage"),
-        ("district", "0007_auto_20201014_1232"),
-    ]
-
-    operations = [
-        migrations.CreateModel(
-            name="DistrictContact",
-            fields=[
-                (
-                    "page_ptr",
-                    models.OneToOneField(
-                        auto_created=True,
-                        on_delete=django.db.models.deletion.CASCADE,
-                        parent_link=True,
-                        primary_key=True,
-                        serialize=False,
-                        to="wagtailcore.page",
-                    ),
-                ),
-                (
-                    "contact_persons",
-                    wagtail.core.fields.StreamField(
-                        [
-                            (
-                                "item",
-                                wagtail.core.blocks.StructBlock(
-                                    [
-                                        (
-                                            "name",
-                                            wagtail.core.blocks.CharBlock(label="Role"),
-                                        ),
-                                        (
-                                            "person",
-                                            wagtail.core.blocks.PageChooserBlock(
-                                                label="Osoba",
-                                                page_type=["shared.PersonPage"],
-                                            ),
-                                        ),
-                                    ]
-                                ),
-                            )
-                        ],
-                        blank=True,
-                        verbose_name="Kontakty",
-                    ),
-                ),
-                (
-                    "search_image",
-                    models.ForeignKey(
-                        blank=True,
-                        null=True,
-                        on_delete=django.db.models.deletion.SET_NULL,
-                        related_name="+",
-                        to="wagtailimages.image",
-                        verbose_name="Search image",
-                    ),
-                ),
-            ],
-            options={
-                "abstract": False,
-            },
-            bases=(
-                district.models.SubpageMixin,
-                wagtailmetadata.models.MetadataMixin,
-                "wagtailcore.page",
-                models.Model,
-            ),
-        ),
-    ]
diff --git a/district/migrations/0009_auto_20201014_1343.py b/district/migrations/0009_auto_20201014_1343.py
deleted file mode 100644
index de2384d14833f5ede20382a4fd288e34f91fa669..0000000000000000000000000000000000000000
--- a/district/migrations/0009_auto_20201014_1343.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Generated by Django 3.1.1 on 2020-10-14 11:43
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ("district", "0008_districtcontact"),
-    ]
-
-    operations = [
-        migrations.AlterModelOptions(
-            name="districtcontact",
-            options={"verbose_name": "Kontakty"},
-        ),
-        migrations.AddField(
-            model_name="districthomepage",
-            name="contact_phone",
-            field=models.TextField(
-                blank=True, max_length=250, verbose_name="kontaktni telefon"
-            ),
-        ),
-    ]
diff --git a/district/migrations/0010_districttags.py b/district/migrations/0010_districttags.py
deleted file mode 100644
index 342cf1e6a0cd8651d843745f5e16f6aace185c01..0000000000000000000000000000000000000000
--- a/district/migrations/0010_districttags.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# Generated by Django 3.1.1 on 2020-10-20 03:30
-
-import django.db.models.deletion
-import wagtailmetadata.models
-from django.db import migrations, models
-
-import shared.models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ("wagtailimages", "0022_uploadedimage"),
-        ("wagtailcore", "0052_pagelogentry"),
-        ("district", "0009_auto_20201014_1343"),
-    ]
-
-    operations = [
-        migrations.CreateModel(
-            name="DistrictTags",
-            fields=[
-                (
-                    "page_ptr",
-                    models.OneToOneField(
-                        auto_created=True,
-                        on_delete=django.db.models.deletion.CASCADE,
-                        parent_link=True,
-                        primary_key=True,
-                        serialize=False,
-                        to="wagtailcore.page",
-                    ),
-                ),
-                (
-                    "search_image",
-                    models.ForeignKey(
-                        blank=True,
-                        null=True,
-                        on_delete=django.db.models.deletion.SET_NULL,
-                        related_name="+",
-                        to="wagtailimages.image",
-                        verbose_name="Search image",
-                    ),
-                ),
-            ],
-            options={
-                "verbose_name": "Stránka s tagy",
-            },
-            bases=(
-                shared.models.SharedSubpageMixin,
-                wagtailmetadata.models.MetadataMixin,
-                "wagtailcore.page",
-                models.Model,
-            ),
-        ),
-    ]
diff --git a/district/models.py b/district/models.py
index e79577c21ef9bb6a2a54b6e63a522d05e387a6d6..25dcf9fe051889ea5f0152fe841976944c47c263 100644
--- a/district/models.py
+++ b/district/models.py
@@ -1,13 +1,18 @@
+import random
+
 from django.core.paginator import Paginator
 from django.db import models
 from django.utils.translation import gettext_lazy
+from modelcluster.contrib.taggit import ClusterTaggableManager
+from modelcluster.fields import ParentalKey
+from taggit.models import TaggedItemBase
 from wagtail.admin.edit_handlers import FieldPanel, MultiFieldPanel, StreamFieldPanel
 from wagtail.core import blocks
 from wagtail.core.fields import StreamField
 from wagtail.core.models import Page
 from wagtailmetadata.models import MetadataPageMixin
 
-from shared.models import Article, PeoplePage, SubpageMixin
+from shared.models import ArticleMixin, Person, SubpageMixin
 
 
 class DistrictHomePage(MetadataPageMixin, Page):
@@ -34,7 +39,7 @@ class DistrictHomePage(MetadataPageMixin, Page):
 
     # Lide uvedeni v paticce
     footperson_coord = models.ForeignKey(
-        "shared.PersonPage",
+        Person,
         verbose_name="Koordinátor",
         on_delete=models.PROTECT,
         null=True,
@@ -42,7 +47,7 @@ class DistrictHomePage(MetadataPageMixin, Page):
         related_name="footperson_coord",
     )
     footperson_electman = models.ForeignKey(
-        "shared.PersonPage",
+        Person,
         verbose_name="Volební manažer",
         on_delete=models.PROTECT,
         null=True,
@@ -50,7 +55,7 @@ class DistrictHomePage(MetadataPageMixin, Page):
         related_name="footperson_electman",
     )
     footperson_media = models.ForeignKey(
-        "shared.PersonPage",
+        Person,
         verbose_name="Kontakt pro média",
         on_delete=models.PROTECT,
         null=True,
@@ -101,11 +106,12 @@ class DistrictHomePage(MetadataPageMixin, Page):
     ]
 
     ### RELATIONS
+
     subpage_types = [
-        "shared.PeoplePage",
-        "DistrictArticles",
-        "DistrictContact",
-        "DistrictTags",
+        "district.DistrictArticlesPage",
+        "district.DistrictContactPage",
+        "district.DistrictPeoplePage",
+        "district.DistrictTagsPage",
     ]
 
     ### OTHERS
@@ -118,30 +124,56 @@ class DistrictHomePage(MetadataPageMixin, Page):
 
     @property
     def articles(self):
-        return self.get_descendants().type(Article).live().specific()
+        return self.get_descendants().type(DistrictArticlePage).live().specific()
 
     @property
     def articles_page(self):
-        return self._first_subpage_of_type(DistrictArticles)
+        return self._first_subpage_of_type(DistrictArticlesPage)
 
     @property
     def people_page(self):
-        return self._first_subpage_of_type(PeoplePage)
+        return self._first_subpage_of_type(DistrictPeoplePage)
 
     @property
     def contact_page(self):
-        return self._first_subpage_of_type(DistrictContact)
+        return self._first_subpage_of_type(DistrictContactPage)
 
     @property
     def tags_page(self):
-        return self._first_subpage_of_type(DistrictTags)
+        return self._first_subpage_of_type(DistrictTagsPage)
 
     @property
     def root_page(self):
         return self
 
 
-class DistrictArticles(SubpageMixin, MetadataPageMixin, Page):
+class DistrictArticleTag(TaggedItemBase):
+    content_object = ParentalKey(
+        "district.DistrictArticlePage", on_delete=models.CASCADE
+    )
+
+
+class DistrictArticlePage(ArticleMixin, SubpageMixin, MetadataPageMixin, Page):
+    ### FIELDS
+
+    tags = ClusterTaggableManager(through=DistrictArticleTag, blank=True)
+
+    ### PANELS
+
+    content_panels = ArticleMixin.content_panels + [FieldPanel("tags")]
+
+    ### RELATIONS
+
+    parent_page_types = ["district.DistrictArticlesPage"]
+    subpage_types = []
+
+    ### OTHERS
+
+    class Meta:
+        verbose_name = "Aktualita"
+
+
+class DistrictArticlesPage(SubpageMixin, MetadataPageMixin, Page):
     ### FIELDS
 
     max_items = models.IntegerField(
@@ -156,9 +188,10 @@ class DistrictArticles(SubpageMixin, MetadataPageMixin, Page):
 
     settings_panels = []
 
-    subpage_types = [
-        "shared.Article",
-    ]
+    ### RELATIONS
+
+    parent_page_types = ["district.DistrictHomePage"]
+    subpage_types = ["district.DistrictArticlePage"]
 
     ### OTHERS
 
@@ -174,35 +207,54 @@ class DistrictArticles(SubpageMixin, MetadataPageMixin, Page):
         return context
 
 
-class DistrictContact(SubpageMixin, MetadataPageMixin, Page):
+class DistrictContactPage(SubpageMixin, MetadataPageMixin, Page):
     class ContactItemBlock(blocks.StructBlock):
         name = blocks.CharBlock(label="Role")
         person = blocks.PageChooserBlock(
             label="Osoba",
-            page_type=["shared.PersonPage"],
+            page_type=["district.DistrictPersonPage"],
         )
 
         class Meta:
             label = "Kontakt"
 
-    contact_persons = StreamField(
+    ### FIELDS
+
+    contact_people = StreamField(
         [("item", ContactItemBlock())],
         verbose_name="Kontakty",
         blank=True,
     )
 
+    ### PANELS
+
     content_panels = Page.content_panels + [
-        StreamFieldPanel("contact_persons"),
+        StreamFieldPanel("contact_people"),
     ]
 
+    ### RELATIONS
+
+    parent_page_types = ["district.DistrictHomePage"]
+    subpage_types = []
+
+    ### OTHERS
+
     class Meta:
         verbose_name = "Kontakty"
 
 
-class DistrictTags(SubpageMixin, MetadataPageMixin, Page):
+class DistrictTagsPage(SubpageMixin, MetadataPageMixin, Page):
+    ### PANELS
 
     settings_panels = []
 
+    ### RELATIONS
+
+    parent_page_types = ["district.DistrictHomePage"]
+    subpage_types = []
+
+    ### OTHERS
+
     class Meta:
         verbose_name = "Stránka s tagy"
 
@@ -220,3 +272,63 @@ class DistrictTags(SubpageMixin, MetadataPageMixin, Page):
 
         context["tags"] = tags
         return context
+
+
+class DistrictPersonPage(SubpageMixin, MetadataPageMixin, Page):
+    ### FIELDS
+
+    person = models.ForeignKey(Person, on_delete=models.PROTECT, null=True)
+    perex = models.TextField("Perex osoby", blank=True)
+
+    ### PANELS
+
+    content_panels = Page.content_panels + [
+        FieldPanel("person"),
+        FieldPanel("perex"),
+    ]
+
+    ### RELATIONS
+
+    parent_page_types = ["district.DistrictPeoplePage"]
+    subpage_types = []
+
+    ### OTHERS
+
+    class Meta:
+        verbose_name = "Detail osoby"
+
+    @property
+    def pageperex(self):
+        """Vraci perex Pirata nejblizzsi lokalnimu kontextu.
+        Zamerne jiny nazev, aby v template bylo na vyber z x.perex, x.person.perex a x.pageperex
+        """
+        return self.perex or self.person.perex
+
+    def get_context(self, request):
+        context = super().get_context(request)
+        # Na strance detailu cloveka se vpravo zobrazuji 3 dalsi nahodne profily
+        context["random_people"] = list(
+            self.get_siblings(inclusive=False).live().specific()
+        )
+        random.shuffle(context["random_people"])
+        context["random_people"] = context["random_people"][:3]
+        return context
+
+
+class DistrictPeoplePage(SubpageMixin, MetadataPageMixin, Page):
+    settings_panels = []
+
+    ### RELATIONS
+
+    parent_page_types = ["district.DistrictHomePage"]
+    subpage_types = ["district.DistrictPersonPage"]
+
+    ### OTHERS
+
+    class Meta:
+        verbose_name = "Lidé"
+
+    def get_context(self, request):
+        context = super().get_context(request)
+        context["people"] = self.get_children().live().specific()
+        return context