# Generated by Django 6.0.3 on 2026-03-08 14:36 import django.contrib.auth.models import django.contrib.auth.validators import django.db.models.deletion import django.utils.timezone from django.conf import settings from django.db import migrations, models class Migration(migrations.Migration): initial = True dependencies = [ ("auth", "0012_alter_user_first_name_max_length"), ] operations = [ migrations.CreateModel( name="Airing", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("starts_at", models.DateTimeField(db_index=True)), ("ends_at", models.DateTimeField(db_index=True)), ( "slot_kind", models.CharField( choices=[ ("program", "Program"), ("commercial", "Commercial"), ("bumper", "Bumper"), ("interstitial", "Interstitial"), ("station_id", "Station ID"), ], max_length=24, ), ), ( "status", models.CharField( choices=[ ("scheduled", "Scheduled"), ("playing", "Playing"), ("played", "Played"), ("skipped", "Skipped"), ("interrupted", "Interrupted"), ("cancelled", "Cancelled"), ], db_index=True, default="scheduled", max_length=24, ), ), ( "source_reason", models.CharField( choices=[ ("template", "Template"), ("autofill", "Autofill"), ("manual", "Manual"), ("recovery", "Recovery"), ], max_length=24, ), ), ("generation_batch_uuid", models.UUIDField()), ("created_at", models.DateTimeField(auto_now_add=True)), ], ), migrations.CreateModel( name="CommercialPolicy", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("name", models.CharField(max_length=255, unique=True)), ( "mode", models.CharField( choices=[ ("none", "None"), ("replace_breaks", "Replace Breaks"), ("fill_to_target", "Fill to Target"), ("probabilistic", "Probabilistic"), ], max_length=24, ), ), ("target_break_seconds", models.IntegerField(blank=True, null=True)), ("max_break_seconds", models.IntegerField(blank=True, null=True)), ("allow_same_ad_back_to_back", models.BooleanField(default=False)), ("description", models.TextField(blank=True, null=True)), ], ), migrations.CreateModel( name="Series", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("title", models.CharField(max_length=255)), ("description", models.TextField(blank=True, null=True)), ("release_year", models.IntegerField(blank=True, null=True)), ("created_at", models.DateTimeField(auto_now_add=True)), ], ), migrations.CreateModel( name="AppUser", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("password", models.CharField(max_length=128, verbose_name="password")), ( "last_login", models.DateTimeField( blank=True, null=True, verbose_name="last login" ), ), ( "is_superuser", models.BooleanField( default=False, help_text="Designates that this user has all permissions without explicitly assigning them.", verbose_name="superuser status", ), ), ( "username", models.CharField( error_messages={ "unique": "A user with that username already exists." }, help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.", max_length=150, unique=True, validators=[ django.contrib.auth.validators.UnicodeUsernameValidator() ], verbose_name="username", ), ), ( "first_name", models.CharField( blank=True, max_length=150, verbose_name="first name" ), ), ( "last_name", models.CharField( blank=True, max_length=150, verbose_name="last name" ), ), ( "email", models.EmailField( blank=True, max_length=254, verbose_name="email address" ), ), ( "is_staff", models.BooleanField( default=False, help_text="Designates whether the user can log into this admin site.", verbose_name="staff status", ), ), ( "is_active", models.BooleanField( default=True, help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.", verbose_name="active", ), ), ( "date_joined", models.DateTimeField( default=django.utils.timezone.now, verbose_name="date joined" ), ), ( "groups", models.ManyToManyField( blank=True, help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.", related_name="user_set", related_query_name="user", to="auth.group", verbose_name="groups", ), ), ( "user_permissions", models.ManyToManyField( blank=True, help_text="Specific permissions for this user.", related_name="user_set", related_query_name="user", to="auth.permission", verbose_name="user permissions", ), ), ], options={ "verbose_name": "user", "verbose_name_plural": "users", "abstract": False, }, managers=[ ("objects", django.contrib.auth.models.UserManager()), ], ), migrations.CreateModel( name="AiringEvent", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "event_type", models.CharField( choices=[ ("scheduled", "Scheduled"), ("started", "Started"), ("ended", "Ended"), ("skipped", "Skipped"), ("interrupted", "Interrupted"), ("resumed", "Resumed"), ("cancelled", "Cancelled"), ], max_length=24, ), ), ("event_at", models.DateTimeField(auto_now_add=True)), ("details_json", models.JSONField(default=dict)), ( "airing", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to="core.airing" ), ), ], ), migrations.CreateModel( name="Channel", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("name", models.CharField(max_length=255)), ("slug", models.SlugField(max_length=64, unique=True)), ("channel_number", models.IntegerField(blank=True, null=True)), ("description", models.TextField(blank=True, null=True)), ("timezone_name", models.CharField(default="UTC", max_length=64)), ( "visibility", models.CharField( choices=[ ("private", "Private"), ("shared", "Shared"), ("public", "Public"), ], default="private", max_length=16, ), ), ( "scheduling_mode", models.CharField( choices=[ ("template_driven", "Template Driven"), ("algorithmic", "Algorithmic"), ("mixed", "Mixed"), ], default="template_driven", max_length=24, ), ), ("is_active", models.BooleanField(default=True)), ("created_at", models.DateTimeField(auto_now_add=True)), ("updated_at", models.DateTimeField(auto_now=True)), ( "owner_user", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, ), ), ], ), migrations.AddField( model_name="airing", name="channel", field=models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to="core.channel" ), ), migrations.CreateModel( name="ContentRating", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("system_name", models.CharField(max_length=64)), ("code", models.CharField(max_length=32)), ("description", models.TextField(blank=True, null=True)), ("min_age", models.IntegerField(blank=True, null=True)), ], options={ "constraints": [ models.UniqueConstraint( fields=("system_name", "code"), name="unique_content_rating" ) ], }, ), migrations.CreateModel( name="Genre", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("name", models.CharField(max_length=128, unique=True)), ("description", models.TextField(blank=True, null=True)), ( "parent_genre", models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to="core.genre", ), ), ], ), migrations.AddField( model_name="channel", name="default_genre", field=models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to="core.genre", ), ), migrations.CreateModel( name="Library", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("name", models.CharField(max_length=255)), ("description", models.TextField(blank=True, null=True)), ( "visibility", models.CharField( choices=[ ("private", "Private"), ("shared", "Shared"), ("public", "Public"), ], default="private", max_length=16, ), ), ("created_at", models.DateTimeField(auto_now_add=True)), ("updated_at", models.DateTimeField(auto_now=True)), ( "owner_user", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, ), ), ], ), migrations.AddField( model_name="channel", name="library", field=models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to="core.library" ), ), migrations.CreateModel( name="LibraryMember", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "role", models.CharField( choices=[ ("viewer", "Viewer"), ("editor", "Editor"), ("manager", "Manager"), ], max_length=16, ), ), ("created_at", models.DateTimeField(auto_now_add=True)), ( "library", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to="core.library" ), ), ( "user", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, ), ), ], ), migrations.CreateModel( name="MediaCollection", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("name", models.CharField(max_length=255)), ( "collection_type", models.CharField( choices=[("manual", "Manual"), ("smart", "Smart")], max_length=24, ), ), ("definition_json", models.JSONField(default=dict)), ("created_at", models.DateTimeField(auto_now_add=True)), ("updated_at", models.DateTimeField(auto_now=True)), ( "library", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to="core.library" ), ), ], ), migrations.CreateModel( name="ChannelBranding", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("logo_path", models.TextField(blank=True, null=True)), ("station_id_audio_path", models.TextField(blank=True, null=True)), ("config_json", models.JSONField(default=dict)), ( "channel", models.OneToOneField( on_delete=django.db.models.deletion.CASCADE, to="core.channel" ), ), ( "commercial_policy", models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to="core.commercialpolicy", ), ), ( "bumper_collection", models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="branded_channels_bumpers", to="core.mediacollection", ), ), ( "fallback_fill_collection", models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="branded_channels_fallback", to="core.mediacollection", ), ), ], ), migrations.CreateModel( name="MediaItem", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("title", models.CharField(max_length=255)), ("sort_title", models.CharField(blank=True, max_length=255, null=True)), ("description", models.TextField(blank=True, null=True)), ( "item_kind", models.CharField( choices=[ ("movie", "Movie"), ("episode", "Episode"), ("special", "Special"), ("music_video", "Music Video"), ("bumper", "Bumper"), ("interstitial", "Interstitial"), ("commercial", "Commercial"), ], db_index=True, max_length=24, ), ), ("season_number", models.IntegerField(blank=True, null=True)), ("episode_number", models.IntegerField(blank=True, null=True)), ("release_year", models.IntegerField(blank=True, null=True)), ("runtime_seconds", models.PositiveIntegerField()), ("file_path", models.TextField()), ("file_hash", models.CharField(blank=True, max_length=128, null=True)), ("thumbnail_path", models.TextField(blank=True, null=True)), ( "language_code", models.CharField(blank=True, max_length=16, null=True), ), ("is_active", models.BooleanField(default=True)), ("date_added_at", models.DateTimeField(auto_now_add=True)), ("metadata_json", models.JSONField(default=dict)), ( "content_rating", models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to="core.contentrating", ), ), ( "genres", models.ManyToManyField( blank=True, related_name="media_items", to="core.genre" ), ), ], ), migrations.CreateModel( name="MediaCollectionItem", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("sort_order", models.IntegerField(default=0)), ( "media_collection", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to="core.mediacollection", ), ), ( "media_item", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to="core.mediaitem" ), ), ], ), migrations.AddField( model_name="mediacollection", name="media_items", field=models.ManyToManyField( through="core.MediaCollectionItem", to="core.mediaitem" ), ), migrations.AddField( model_name="airing", name="media_item", field=models.ForeignKey( on_delete=django.db.models.deletion.RESTRICT, to="core.mediaitem" ), ), migrations.CreateModel( name="MediaResumePoint", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("resume_seconds", models.PositiveIntegerField()), ("updated_at", models.DateTimeField(auto_now=True)), ( "media_item", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to="core.mediaitem" ), ), ( "user", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, ), ), ], ), migrations.CreateModel( name="MediaSource", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("name", models.CharField(max_length=255)), ( "source_type", models.CharField( choices=[ ("local_directory", "Local Directory"), ("network_share", "Network Share"), ("manual_import", "Manual Import"), ("playlist", "Playlist"), ("stream", "Stream"), ("api_feed", "API Feed"), ], max_length=32, ), ), ("uri", models.TextField()), ("recursive_scan", models.BooleanField(default=True)), ("include_commercials", models.BooleanField(default=False)), ("is_active", models.BooleanField(default=True)), ("scan_interval_minutes", models.IntegerField(blank=True, null=True)), ("last_scanned_at", models.DateTimeField(blank=True, null=True)), ("created_at", models.DateTimeField(auto_now_add=True)), ("updated_at", models.DateTimeField(auto_now=True)), ( "library", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to="core.library" ), ), ], ), migrations.AddField( model_name="mediaitem", name="media_source", field=models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to="core.mediasource" ), ), migrations.CreateModel( name="ChannelSourceRule", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "rule_mode", models.CharField( choices=[ ("allow", "Allow"), ("prefer", "Prefer"), ("avoid", "Avoid"), ("block", "Block"), ], max_length=24, ), ), ( "weight", models.DecimalField(decimal_places=4, default=1.0, max_digits=10), ), ("max_items_per_day", models.IntegerField(blank=True, null=True)), ("max_runs_per_day", models.IntegerField(blank=True, null=True)), ("min_repeat_gap_hours", models.IntegerField(blank=True, null=True)), ("active_from", models.DateTimeField(blank=True, null=True)), ("active_to", models.DateTimeField(blank=True, null=True)), ("created_at", models.DateTimeField(auto_now_add=True)), ( "channel", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to="core.channel" ), ), ( "media_collection", models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to="core.mediacollection", ), ), ( "media_source", models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to="core.mediasource", ), ), ], ), migrations.CreateModel( name="MediaSourceRule", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "rule_type", models.CharField( choices=[ ("include_glob", "Include Glob"), ("exclude_glob", "Exclude Glob"), ("include_regex", "Include Regex"), ("exclude_regex", "Exclude Regex"), ], max_length=24, ), ), ("rule_value", models.TextField()), ("sort_order", models.IntegerField(default=0)), ( "media_source", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to="core.mediasource", ), ), ], ), migrations.CreateModel( name="ScheduleBlock", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("name", models.CharField(max_length=255)), ( "block_type", models.CharField( choices=[ ("programming", "Programming"), ("commercial", "Commercial"), ("filler", "Filler"), ("off_air", "Off Air"), ("special_event", "Special Event"), ], max_length=24, ), ), ("start_local_time", models.TimeField()), ("end_local_time", models.TimeField()), ("day_of_week_mask", models.SmallIntegerField()), ("spills_past_midnight", models.BooleanField(default=False)), ( "rotation_strategy", models.CharField( choices=[ ("shuffle", "Shuffle"), ("sequential", "Sequential"), ("least_recent", "Least Recent"), ("weighted_random", "Weighted Random"), ], default="shuffle", max_length=24, ), ), ( "pad_strategy", models.CharField( choices=[ ("hard_stop", "Hard Stop"), ("truncate", "Truncate"), ("fill_with_interstitials", "Fill With Interstitials"), ("allow_overrun", "Allow Overrun"), ], default="fill_with_interstitials", max_length=24, ), ), ("created_at", models.DateTimeField(auto_now_add=True)), ( "default_genre", models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to="core.genre", ), ), ( "max_content_rating", models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="+", to="core.contentrating", ), ), ( "min_content_rating", models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="+", to="core.contentrating", ), ), ( "preferred_collection", models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to="core.mediacollection", ), ), ( "preferred_source", models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to="core.mediasource", ), ), ], ), migrations.CreateModel( name="BlockSlot", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("slot_order", models.IntegerField()), ( "slot_kind", models.CharField( choices=[ ("fixed_item", "Fixed Item"), ("dynamic_pick", "Dynamic Pick"), ("commercial_break", "Commercial Break"), ("bumper", "Bumper"), ("station_id", "Station ID"), ], max_length=24, ), ), ( "expected_duration_seconds", models.IntegerField(blank=True, null=True), ), ("max_duration_seconds", models.IntegerField(blank=True, null=True)), ("is_mandatory", models.BooleanField(default=True)), ("selection_rule_json", models.JSONField(default=dict)), ( "media_collection", models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to="core.mediacollection", ), ), ( "media_item", models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to="core.mediaitem", ), ), ( "schedule_block", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to="core.scheduleblock", ), ), ], ), migrations.AddField( model_name="airing", name="schedule_block", field=models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to="core.scheduleblock", ), ), migrations.CreateModel( name="ScheduleTemplate", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("name", models.CharField(max_length=255)), ("description", models.TextField(blank=True, null=True)), ("timezone_name", models.CharField(max_length=64)), ("valid_from_date", models.DateField(blank=True, null=True)), ("valid_to_date", models.DateField(blank=True, null=True)), ("priority", models.IntegerField(default=0)), ("is_active", models.BooleanField(default=True)), ("created_at", models.DateTimeField(auto_now_add=True)), ("updated_at", models.DateTimeField(auto_now=True)), ( "channel", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to="core.channel" ), ), ], ), migrations.AddField( model_name="scheduleblock", name="schedule_template", field=models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to="core.scheduletemplate" ), ), migrations.AddField( model_name="airing", name="schedule_template", field=models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to="core.scheduletemplate", ), ), migrations.AddField( model_name="mediaitem", name="series", field=models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to="core.series", ), ), migrations.CreateModel( name="UserChannelState", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("is_favorite", models.BooleanField(default=False)), ("last_tuned_at", models.DateTimeField(blank=True, null=True)), ("created_at", models.DateTimeField(auto_now_add=True)), ("updated_at", models.DateTimeField(auto_now=True)), ( "channel", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to="core.channel" ), ), ( "last_known_airing", models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to="core.airing", ), ), ( "user", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, ), ), ], ), migrations.CreateModel( name="WatchSession", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("started_at", models.DateTimeField(db_index=True)), ("ended_at", models.DateTimeField(blank=True, null=True)), ("position_seconds", models.PositiveIntegerField(default=0)), ("client_id", models.CharField(blank=True, max_length=128, null=True)), ("session_metadata", models.JSONField(default=dict)), ( "airing", models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to="core.airing", ), ), ( "channel", models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to="core.channel", ), ), ( "user", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, ), ), ], ), migrations.CreateModel( name="ChannelMember", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "role", models.CharField( choices=[ ("viewer", "Viewer"), ("editor", "Editor"), ("manager", "Manager"), ], max_length=16, ), ), ("created_at", models.DateTimeField(auto_now_add=True)), ( "channel", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to="core.channel" ), ), ( "user", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, ), ), ], options={ "constraints": [ models.UniqueConstraint( fields=("channel", "user"), name="unique_channel_member" ) ], }, ), migrations.AddConstraint( model_name="library", constraint=models.UniqueConstraint( fields=("owner_user", "name"), name="unique_library_name_per_user" ), ), migrations.AddConstraint( model_name="channel", constraint=models.UniqueConstraint( fields=("library", "name"), name="unique_channel_name_per_library" ), ), migrations.AddConstraint( model_name="channel", constraint=models.UniqueConstraint( fields=("library", "channel_number"), name="unique_channel_number_per_library", ), ), migrations.AddConstraint( model_name="librarymember", constraint=models.UniqueConstraint( fields=("library", "user"), name="unique_library_member" ), ), migrations.AddConstraint( model_name="mediacollection", constraint=models.UniqueConstraint( fields=("library", "name"), name="unique_media_collection_name_per_library", ), ), migrations.AddConstraint( model_name="mediaresumepoint", constraint=models.UniqueConstraint( fields=("user", "media_item"), name="unique_media_resume_point" ), ), migrations.AddConstraint( model_name="mediasource", constraint=models.UniqueConstraint( fields=("library", "name"), name="unique_media_source_name_per_library" ), ), migrations.AddConstraint( model_name="channelsourcerule", constraint=models.CheckConstraint( condition=models.Q( models.Q( ("media_collection__isnull", True), ("media_source__isnull", False), ), models.Q( ("media_collection__isnull", False), ("media_source__isnull", True), ), _connector="OR", ), name="exactly_one_source_target_channel_source_rule", ), ), migrations.AddConstraint( model_name="blockslot", constraint=models.UniqueConstraint( fields=("schedule_block", "slot_order"), name="unique_slot_order_per_block", ), ), migrations.AddConstraint( model_name="scheduletemplate", constraint=models.UniqueConstraint( fields=("channel", "name"), name="unique_schedule_template_name_per_channel", ), ), migrations.AddConstraint( model_name="mediaitem", constraint=models.UniqueConstraint( fields=("media_source", "file_path"), name="unique_media_item_path_per_source", ), ), migrations.AddConstraint( model_name="userchannelstate", constraint=models.UniqueConstraint( fields=("user", "channel"), name="unique_user_channel_state" ), ), ]