diff --git a/main/migrations/0054_mainpersonpage_ical_calendar_url_and_more.py b/main/migrations/0054_mainpersonpage_ical_calendar_url_and_more.py
new file mode 100644
index 0000000000000000000000000000000000000000..c7410e365de3360ba4c6516822775da4411d35a0
--- /dev/null
+++ b/main/migrations/0054_mainpersonpage_ical_calendar_url_and_more.py
@@ -0,0 +1,23 @@
+# Generated by Django 4.1.6 on 2023-04-12 12:06
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('main', '0053_merge_20230406_1446'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='mainpersonpage',
+            name='ical_calendar_url',
+            field=models.URLField(blank=True, help_text='Musí být ve formátu iCal. V Google kalendáři lze exportovat v nastavení (TODO).', max_length=256, null=True, verbose_name='iCal adresa kalendáře'),
+        ),
+        migrations.AddField(
+            model_name='mainpersonpage',
+            name='nextcloud_calendar_url',
+            field=models.URLField(blank=True, help_text='V nastavení kalendáře klikni na ikonu "+" vedle "odkaz na sdílení" a vlož zkopírovaný odkaz.', max_length=256, null=True, verbose_name='Adresa kalendáře v Mraku'),
+        ),
+    ]
diff --git a/main/models.py b/main/models.py
index a28e04ff5a1ac273873c5bc723fe8c976e2a70e5..dea07d34bfa4f6f9818db09fe54aab60aaa5f9c7 100644
--- a/main/models.py
+++ b/main/models.py
@@ -5,6 +5,7 @@ from django.conf import settings
 from django.contrib import messages
 from django.core.paginator import Paginator
 from django.db import models
+from django.forms import ValidationError
 from django.http import HttpResponseRedirect, JsonResponse
 from django.shortcuts import render
 from django.utils import timezone
@@ -800,6 +801,23 @@ class MainPersonPage(ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin,
 
     email = models.CharField("E-mail", max_length=128, blank=True, null=True)
     phone = models.CharField("Telefonní kontakt", max_length=16, blank=True, null=True)
+    ical_calendar_url = models.URLField(
+        "iCal adresa kalendáře",
+        max_length=256,
+        blank=True,
+        null=True,
+        help_text="Musí být ve formátu iCal. V Google kalendáři lze exportovat v nastavení (TODO).",
+    )
+    nextcloud_calendar_url = models.URLField(
+        "Adresa kalendáře v Mraku",
+        max_length=256,
+        blank=True,
+        null=True,
+        help_text=(
+            'V nastavení kalendáře klikni na ikonu "+" vedle "odkaz na sdílení" '
+            "a vlož zkopírovaný odkaz."
+        )
+    )
 
     settings_panels = []
 
@@ -820,6 +838,13 @@ class MainPersonPage(ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin,
         FieldPanel("text"),
         FieldPanel("email"),
         FieldPanel("phone"),
+        MultiFieldPanel(
+            [
+                FieldPanel("ical_calendar_url"),
+                FieldPanel("nextcloud_calendar_url"),
+            ],
+            "Kalendář",
+        ),
         FieldPanel("social_links"),
         FieldPanel("people"),
     ]
@@ -845,6 +870,28 @@ class MainPersonPage(ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin,
 
     ### OTHERS
 
+    def clean(self) -> None:
+        cleaned_data = super().clean()
+
+        BOTH_CALENDARS_DEFINED_ERROR_MESSAGE = (
+            "Nemůžeš definovat kalendář z Mraku a v iCal formátu najednou."
+        )
+
+        if (
+            cleaned_data.get("ical_calendar_url")
+            and cleaned_data.get("nextcloud_calendar_url")
+        ):
+            self.add_error(
+                "ical_calendar_url",
+                BOTH_CALENDARS_DEFINED_ERROR_MESSAGE
+            )
+            self.add_error(
+                "nextcloud_calendar_url",
+                BOTH_CALENDARS_DEFINED_ERROR_MESSAGE
+            )
+
+        return cleaned_data
+
     class Meta:
         verbose_name = "Detail osoby"
         # ordering = ("title",)