# Generated by Django 6.0.5 on 2026-06-04 12:31 import datetime import django.db.models.deletion import filer.fields.file import filer.fields.image from django.conf import settings from django.db import migrations, models class Migration(migrations.Migration): initial = True dependencies = [ ('filer', '0018_alter_file_options'), migrations.swappable_dependency(settings.FILER_IMAGE_MODEL), ] operations = [ migrations.CreateModel( name='TbArticle', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('s_article_title', models.CharField(default='', help_text='Технический заголовок статьи для внутреннего использования, например: "Album: Abbey Road" или "Bio: The Beatles".', max_length=255, unique=True, verbose_name='Технический заголовок')), ('l_article_type', models.CharField(blank=True, choices=[('artist', 'Artis: артист, группа или бренд'), ('item', 'Item: Альбом, релиз или товар (кассета, hifi, аксессуар)'), ('offer', 'Offer: конкретное предложение от продавца'), ('seller', 'Seller: продавец или магазин'), ('blog', 'Новость или блог'), ('action', 'Спецпредложение, акция, распродажа и т.д.'), ('to_main', 'Текст/Блок для главной страницы'), ('adv', 'Реклама или баннер'), ('???', 'Другое')], db_index=True, default='???', max_length=7, verbose_name='Тип статьи')), ('b_article_published', models.BooleanField(db_index=True, default=True, verbose_name='Опубликовано')), ('t_article_started', models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='Дата начала публикации')), ('t_article_ended', models.DateTimeField(blank=True, db_index=True, default=None, help_text='Если указано, статья будет отображаться только между датой начала и датой окончания публикации. Если не указано, статья будет отображаться всегда (или до тех пор, пока не будет удалена или снята с публикации через `b_article_published`)', null=True, verbose_name='Дата окончания публикации')), ('s_article_title_html', models.CharField(blank=True, default='', help_text='Заголовок статьи, например: "Описание релиза Abbey Road" или "Биография группы The Beatles". Может содержать HTML-разметку для типографирования (html-мнемоники и -теги). Если не указано, будет отображаться без заголовка.', max_length=255, verbose_name='Заголовок')), ('s_article_teaser_html', models.TextField(blank=True, default='', help_text='Короткий анонс статьи, который будет отображаться в списках. Может содержать HTML-вёрсту (теги, мнемоники, спецсимволы) для типографирования.', null=True, verbose_name='Тизер статьи')), ('s_article_content_html', models.TextField(blank=True, default='', help_text='Полный текст статьи. Может содержать HTML-вёрсту (теги, мнемоники, спецсимволы) для типографирования.', null=True, verbose_name='Статья')), ('i_article_views', models.IntegerField(db_index=True, default=0, verbose_name='Число просмотров')), ('i_article_favorites', models.IntegerField(db_index=True, default=0, verbose_name='Число в избранном')), ('slug', models.SlugField(default='', max_length=255, unique=True, verbose_name='Слаг статьи')), ('seo_title', models.CharField(blank=True, default='', help_text='SEO Title для статьи. Если не указано, будет использоваться заголовок статьи (s_article_title_html) без HTML-тегов.', max_length=255, verbose_name='SEO Title')), ('seo_description', models.CharField(blank=True, default='', help_text='SEO Description для статьи. Если не указано, будет использоваться обрезанный тизер статьи (s_article_teaser_html) без HTML-тегов.', max_length=255, verbose_name='SEO Description')), ('seo_keywords', models.CharField(blank=True, default='', help_text='SEO Keywords для статьи, через запятую. Например: "The Beatles, Abbey Road, Vinyl, 1969"', max_length=255, verbose_name='SEO Keywords')), ('t_article_created', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')), ('t_article_updated', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')), ], options={ 'verbose_name': 'Статья', 'verbose_name_plural': 'Статьи', 'ordering': ('-t_article_updated', '-t_article_created', 's_article_title'), }, ), migrations.CreateModel( name='TbFormat', fields=[ ('id', models.SmallAutoField(primary_key=True, serialize=False)), ('s_format', models.CharField(db_index=True, help_text='Название формата носителя, например: "LP", "CD", "Blu-ray", "Compact Cassette", "MiniDisc", "Hi-Fi", "Accessory" и т.д.', max_length=16, unique=True, verbose_name='Формат носителя')), ('s_format_slug', models.SlugField(max_length=16, unique=True, verbose_name='Слаг')), ], options={ 'verbose_name': 'Формат носителя', 'verbose_name_plural': 'Форматы носителей', 'ordering': ('s_format',), }, ), migrations.CreateModel( name='TbMusicStyle', fields=[ ('id', models.SmallAutoField(primary_key=True, serialize=False)), ('s_style_name', models.CharField(db_index=True, help_text='Основное название стиля. Например: "Rock", "Jazz", "Classical"', max_length=100, unique=True, verbose_name='Стиль (канонический)')), ('s_style_slug', models.SlugField(editable=False, help_text='Автоматически генерируется из названия. Используется в URL и API.', unique=True, verbose_name='Слаг (уникальный идентификатор)')), ('j_style_synonyms', models.JSONField(blank=True, default=list, help_text='Список вариантов названия из Discogs, MusicBrainz и т.д. для матчинга. Пример: ["rock", "Rock Music", "Rock & Roll", "Hard Rock"]', verbose_name='Синонимы из источников')), ('t_style_created', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')), ('t_style_updated', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')), ], options={ 'verbose_name': 'Музыкальный стиль', 'verbose_name_plural': 'Музыкальные стили', 'ordering': ('s_style_name',), }, ), migrations.CreateModel( name='TbArtist', fields=[ ('id', models.SmallAutoField(primary_key=True, serialize=False)), ('s_artist', models.CharField(help_text='Техническое название исполнителя для внутреннего использования, например: "The Beatles" или"David Bowie".', max_length=128, unique=True, verbose_name='Исполнитель')), ('j_artist_metadata', models.JSONField(blank=True, default=list, help_text='Включая варианты написания в источниках Список вариантов: ["The Beatles", "Beatles", "Beatles, The"]', null=True, verbose_name='Метаданные JSON')), ('t_artist_created', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')), ('t_artist_updated', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')), ('k_artist_to_article', models.OneToOneField(blank=True, default=None, help_text='Связанная статья об исполнителе (Типографированные заголовок, тизер и текст статьи. Так же через статью может быть получена картинка, seo атрибуты, слаг (обязательно) и т.п.)
ОБЯЗАТЕЛЬНО УКАЗЫВАТЬ т.к. через статью получаем слаг для URL артиста.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='article_to_artist', to='frontend.tbarticle', verbose_name='Связанная статья')), ], options={ 'verbose_name': 'Исполнитель', 'verbose_name_plural': 'Исполнители', 'ordering': ('s_artist',), }, ), migrations.CreateModel( name='TbImage', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('l_img_source', models.CharField(choices=[('parser', 'Загружено парсером (из Discogs, Meshok или другого сайта)'), ('manual', 'Ручная загрузка пользователем'), ('vendor', 'От продавца'), ('other', 'Другое')], default='manual', help_text='Как был получен этот снимок: загружен вручную, получен парсером из внешнего источника (например, Discogs), предоставлен продавцом и т.д.', max_length=10, verbose_name='Источник')), ('l_img_reality', models.CharField(choices=[('real', 'Реальная фотография товара'), ('abstract', 'Абстрактное (из внешнего источника)')], default='abstract', help_text='Реальная фотография товара или картинка из внешнего источника?', max_length=10, verbose_name='Тип снимка')), ('s_img_src_url', models.URLField(blank=True, help_text='Если изображение взято из внешнего источника (например, Discogs)', null=True, verbose_name='URL источника')), ('i_img_sort', models.IntegerField(db_index=True, default=0, help_text='Порядок отображения изображений. Чем меньше число, тем выше в списке. Можно использовать для указания обложки (0), задника (1) и т.д.', verbose_name='Cортировка')), ('f_img_confidence_score', models.FloatField(blank=True, default=None, help_text='0.0 - 1.0, насколько уверены, что это правильное изображение', null=True, verbose_name='Уверенность (для автоматических данных)')), ('s_img_copyright', models.CharField(blank=True, default='', help_text='Например: "© 2024 User" или "CC-BY"', max_length=255, verbose_name='Авторские права / Лицензия')), ('t_img_created', models.DateTimeField(auto_now_add=True, verbose_name='Дата добавления')), ('t_img_updated', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')), ('image', filer.fields.image.FilerImageField(blank=True, help_text='Файл изображения, загруженный через django_filer.', null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.FILER_IMAGE_MODEL, verbose_name='Файл изображения')), ], options={ 'verbose_name': 'Изображение', 'verbose_name_plural': 'Изображения', 'ordering': ('-t_img_created', 'i_img_sort'), }, ), migrations.AddField( model_name='tbarticle', name='k_article_to_image', field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='image_to_article', to='frontend.tbimage', verbose_name='Изображение для статьи'), ), migrations.CreateModel( name='TbItem', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('s_item', models.CharField(help_text='Техническое название товара (альбома, релиза, аксессуара) для внутреннего использования,например: "Abbey Road (LP)" или "TDK CDing I (кассета для записи)".', max_length=128, unique=True, verbose_name='Товар')), ('s_item_date', models.CharField(blank=True, default='XXXX-XX-XX', help_text='Например: 1969-05-25, или 1969-05-XX (если день неизвестен), или 1969-XX-XX (если известен только год, или XXXX-XX-XX (если дата релиза неизвестна). Менее приоритетное поле для отображения даты релиза, чем t_release_date, так как может содержать неполную дату и/или текстовую информацию. Срабатывает только если t_release_date не указано.', max_length=10, null=True, verbose_name='Дата релиза (str)')), ('t_item_date', models.DateField(blank=True, help_text='Полная дата если известна, например: 1969-09-26. Если точно известен.', null=True, verbose_name='Дата релиза')), ('i_discogs_master_id', models.IntegerField(blank=True, default=None, help_text='Уникальный идентификатор мастер-релиза на Discogs, если он там есть. Например: 306323', null=True, verbose_name='ID на мастер-релиз Discogs')), ('j_item_metadata', models.JSONField(blank=True, default=dict, help_text='Дополнительные данные и метаданные релиза (страна, жанр, количество треков и т.д.) или товавра в виде JSON-словаря. Сюда же включены варианты написания релиза в источниках', null=True, verbose_name='Дополнительные данные')), ('t_item_created', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')), ('t_item_updated', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')), ('k_item_to_article', models.OneToOneField(blank=True, default=None, help_text='Связанная статья об альбоме/релизе/товаре (Типографированные заголовок, тизер и текст статьи. Так же через статью может быть получена картинка, seo атрибуты, слаг (обязательно) и т.п.)
ОБЯЗАТЕЛЬНО УКАЗЫВАТЬ т.к. через статью получаем слаг для URL альбома/релиза/товара.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='article_to_item', to='frontend.tbarticle', verbose_name='Связанная статья')), ('k_item_to_artist', models.ManyToManyField(blank=True, db_index=True, help_text='Один или несколько для коллабораций', related_name='artist_to_item', to='frontend.tbartist', verbose_name='Исполнители')), ], options={ 'verbose_name': 'Товар в каталоге (релиз, носитель, аксессуар)', 'verbose_name_plural': 'Товары в каталоге', 'ordering': ('s_item',), }, ), migrations.CreateModel( name='TbLabel', fields=[ ('id', models.SmallAutoField(primary_key=True, serialize=False)), ('s_label', models.CharField(help_text='Техническое название лейбла. Например: "Sony Records" или "Мелодия"', max_length=128, unique=True, verbose_name='Лейбл')), ('j_label_metadata', models.JSONField(blank=True, default=dict, help_text='JSON: страна лейбла, официальный сайт и т.д.', null=True, verbose_name='Метаданные')), ('t_label_created', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')), ('t_label_updated', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')), ('k_label_to_article', models.OneToOneField(blank=True, default=None, help_text='Связанная статья об лейбле (Типографированные заголовок, тизер и текст статьи. Так же через статью может быть получена картинка, seo атрибуты, слаг (обязательно) и т.п.)
ОБЯЗАТЕЛЬНО УКАЗЫВАТЬ т.к. через статью получаем слаг для URL лейбла.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='article_to_label', to='frontend.tbarticle', verbose_name='Связанная статья')), ], options={ 'verbose_name': 'Лейбл', 'verbose_name_plural': 'Лейблы', 'ordering': ('s_label',), }, ), migrations.AddField( model_name='tbarticle', name='k_article_to_styles', field=models.ManyToManyField(blank=True, db_index=True, help_text='Стили этой статьи/артиста/релиза (Rock, Jazz, Classical, ...)', related_name='style_to_article', to='frontend.tbmusicstyle', verbose_name='Музыкальные стили'), ), migrations.CreateModel( name='TbOffer', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('s_offer', models.CharField(db_index=True, help_text='Техническое название оффера для внутреннего использования, например: "Abbey Road (LP) AnTrop NM/NM (МЗГ)" или "TDK CDing I 60 (б/у) VG/VG (Janan, 198x синяя-градиент)"', max_length=128, verbose_name='Название оффера')), ('s_offer_catalog_num', models.TextField(blank=True, default='', help_text='Например: "SD 16023" или "5099923452355"', verbose_name='Каталожный номер / Barcode')), ('d_offer_date_release', models.DateField(blank=True, default=None, help_text='Дата релиза, если она известна (например, дата выпуска переиздания)', null=True, verbose_name='Дата релиза')), ('i_offer_discogs_id', models.IntegerField(blank=True, default=0, help_text='Уникальный идентификатор релиза на Discogs, если он там есть. Например: 306323', verbose_name='ID на релиз Discogs')), ('l_offer_condition_media', models.CharField(choices=[('s', 'Still Sealed (новое, запечатано)'), ('m', 'Mint (новое, распакованное)'), ('nm', 'Near Mint (почти новое)'), ('vg', 'Very Good (очень хорошее)'), ('g', 'Good (хорошее)'), ('f', 'Fair (удовлетворительное)'), ('p', 'Poor (плохое)'), ('??', 'Other')], default='s', help_text='Состояние носителя (пластинки, CD и т.п.) по шкале от "Still Sealed" (запечатано) до "Poor" (плохое).', max_length=2, verbose_name='Состояние носителя')), ('l_offer_condition_sleeve', models.CharField(choices=[('s', 'Still Sealed (новое, запечатано)'), ('m', 'Mint (новое, распакованное)'), ('nm', 'Near Mint (почти новое)'), ('vg', 'Very Good (очень хорошее)'), ('g', 'Good (хорошее)'), ('f', 'Fair (удовлетворительное)'), ('p', 'Poor (плохое)'), ('??', 'Other')], default='s', help_text='Состояние обложки по шкале от "Still Sealed" (запечатано) до "Poor" (плохое).', max_length=2, verbose_name='Состояние обложки')), ('f_offer_price', models.DecimalField(db_index=True, decimal_places=2, default=0.0, help_text='Цена в валюте источника. Валюта определяется в TbSource: offer.k_offer_to_source.l_currency', max_digits=10, verbose_name='Цена')), ('i_offer_quantity', models.IntegerField(blank=True, default=0, verbose_name='Количество в наличии')), ('i_offer_discount_to_daily_sale', models.IntegerField(blank=True, db_index=True, default=0, help_text='Процент возможной скидки, если участвует в "ежедневной распродаже" или акции. Если указано 0 то данное предложение не может участвовать в распродажах, спецпредложениях и акциях', verbose_name='Скидка')), ('j_offer_metadata', models.JSONField(default=dict, help_text='Дополнительные данные о предложении в виде JSON-словаря.', null=True, verbose_name='Дополнительные данные')), ('s_offer_skip32', models.CharField(help_text='Уникальный код товара для идентификации в корзине и при заказе (чтобы не светить id). Например: "4gfFCJ". Формируется автоматически связкой Skip32 (хаотичное перемешивание) и Base62 (компактная упаковка) из id оффера в методе save().', max_length=12, unique=True, verbose_name='Код товара')), ('i_offer_views', models.IntegerField(db_index=True, default=0, verbose_name='Просмотры')), ('i_offer_favorites', models.IntegerField(db_index=True, default=0, verbose_name='В избранном')), ('t_offer_created', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')), ('t_offer_updated', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')), ('k_offer_to_article', models.ForeignKey(blank=True, default=None, help_text='Связанная статья об оффере (HTML-готовые заголовок, тизер и текст статьи). Так же через статью может быть получена картинка, seo атрибуты, слаг (обязательно) и т.п.)
МОЖНО НЕ УКАЗЫВАТЬ т.к. URL оффера (для корзины) формируется через id или хеш.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='article_to_offer', to='frontend.tbarticle', verbose_name='Связанная статья')), ('k_offer_to_format', models.ManyToManyField(blank=True, db_index=True, help_text='Форматы носителей (пластинка, CD, кассета и т.п.). Можно выбрать несколько.', related_name='format_to_offer', to='frontend.tbformat', verbose_name='Форматы')), ('k_offer_to_image', models.ManyToManyField(blank=True, db_index=True, help_text='Картинки этого товара. Порядок определяется полем i_img_sort в ка��тинке.', related_name='image_to_offer', to='frontend.tbimage', verbose_name='Изображения')), ('k_offer_to_item', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='item_to_offer', to='frontend.tbitem', verbose_name='Релиз (товар)')), ('k_offer_to_label', models.ForeignKey(default=None, help_text='Лейбл, на котором был выпущен релиз, если он известен. Например: Atlantic или Мелодия', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='label_to_offer', to='frontend.tblabel', verbose_name='Лейбл')), ], options={ 'verbose_name': 'Оффер (предложение)', 'verbose_name_plural': 'Офферы (предложения)', 'ordering': ('-t_offer_updated', '-t_offer_created', 's_offer'), }, ), migrations.CreateModel( name='TbOfferHistory', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('f_history_price', models.DecimalField(blank=True, decimal_places=2, default=0.0, max_digits=12, null=True, verbose_name='Старая цена')), ('i_history_quantity', models.IntegerField(default=0, verbose_name='Старое количество')), ('j_history_metadata', models.JSONField(blank=True, default=dict, help_text='Метаданные, указывающие координаты данных внутри источника (например, внутри Excel-файла: название вкладки, номер строки, номер столбца с ценой и количеством, или URL + CSS-селектор для HTML-страницы и т.п.', verbose_name='Метаданные')), ('t_history_created', models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='Дата создания')), ('k_history_to_offer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='offer_to_history', to='frontend.tboffer', verbose_name='Оффер')), ], options={ 'verbose_name': 'История оффера', 'verbose_name_plural': 'Истории офферов', 'ordering': ('-t_history_created',), }, ), migrations.CreateModel( name='TbSeller', fields=[ ('id', models.SmallAutoField(primary_key=True, serialize=False)), ('s_seller', models.CharField(help_text='Техническое название продавца или магазина. Например: Клюква Рекодс. Может совпадать с названием продавца, если лейбл сам реализует свои издания через сайт.', max_length=128, unique=True, verbose_name='Название продавца')), ('l_seller_type', models.CharField(choices=[('seller', 'Продавец'), ('label', 'Лейбл (издатель)'), ('diy', 'Самиздат группы'), ('crowd', 'Краудфандинг'), ('???', 'Другое')], default='seller', max_length=6, verbose_name='Тип продавца')), ('j_seller_metadata', models.JSONField(blank=True, default=dict, help_text='Дополнительные данные о продавце в виде JSON-словаря. Телефон, email, адрес, ссылка на сайт и т.д.', null=True, verbose_name='Дополнительные данные')), ('t_seller_created', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')), ('t_seller_updated', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')), ('k_seller_to_article', models.OneToOneField(blank=True, default=None, help_text='Связанная статья о продавце (HTML-готовые заголовок, тизер и текст статьи). Так же через статью может быть получена картинка, seo атрибуты, слаг (обязательно) и т.п.)
ОБЯЗАТЕЛЬНО УКАЗЫВАТЬ т.к. через статью получаем слаг для URL продавца.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='article_to_seller', to='frontend.tbarticle', verbose_name='Связанная статья')), ], options={ 'verbose_name': 'Продавец', 'verbose_name_plural': 'Продавцы', 'ordering': ('s_seller',), }, ), migrations.CreateModel( name='TbSource', fields=[ ('id', models.SmallAutoField(primary_key=True, serialize=False)), ('l_source_currency', models.CharField(choices=[('rub', 'RUB: российский рубль'), ('usd', 'USD: американский доллар'), ('eur', 'EUR: евро'), ('try', 'TRY: турецкая лира'), ('amd', 'AMD: армянский драм'), ('jpy', 'JPY: японская иена'), ('gbp', 'GBP: британский фунт'), ('cny', 'CNY: китайский юань'), ('byn', 'BYN: белорусский рубль'), ('ton', 'TON: криптовалюта TON'), ('??', 'Other')], default='rub', help_text='В какой валюте указаны цены в этом источнике. Все офферы из этого источника будут в этой валюте.', max_length=3, verbose_name='Валюта источника')), ('s_source_name', models.CharField(blank=True, default='', help_text='Название источника данных (для удобства), например: Предзаказ на RSD-2025 от Полуэкта.', max_length=128, verbose_name='Название источника')), ('l_source_type', models.CharField(choices=[('excel', 'Excel-файл от продавца или издателя'), ('csv', 'CSV-файл от продавца или издателя'), ('url', 'URL страницы с данными (например, HTML-страница с каталогом товаров)'), ('??', 'Другое')], default='excel', help_text='Тип источника данных, например: Excel-файл от продавца или издателя, URL страницы с данными и т.д.', max_length=5, verbose_name='Тип источника')), ('t_source_data', models.DateField(blank=True, default=datetime.date.today, help_text='Дата, к которой относятся данные в источнике. Например, если это исторический Excel-файл.', verbose_name='Дата данных')), ('s_source_url', models.TextField(blank=True, default='', help_text='URL страницы с данными, например, HTML-страница с каталогом товаров. Если данные в источнике представлены в виде файла, можно не указывать URL, а загрузить файл в поле выше.', max_length=255, verbose_name='URL источника')), ('j_source_metadata', models.JSONField(blank=True, default=dict, help_text='Дополнительные данные об источнике (внутреннем устройстве: вкладках и стоkбцах Excel-файла, структуре HTML-страницы и т.п.) в виде JSON-словаря', verbose_name='Дополнительные данные')), ('t_source_created', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')), ('t_source_updated', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')), ('k_source_to_seller', models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='seller_to_source', to='frontend.tbseller', verbose_name='Продавец')), ('source_file', filer.fields.file.FilerFileField(blank=True, help_text='Файл-источник, например, Excel-файл от продавца или издателя. Если данные в источнике представлены на странице в интернете, можно не указывать файл, а указать URL в поле ниже.', null=True, on_delete=django.db.models.deletion.SET_NULL, to='filer.file', verbose_name='Файл-источник')), ], options={ 'verbose_name': 'Источник данных', 'verbose_name_plural': 'Источники данных', 'ordering': ('-t_source_data', '-t_source_created'), }, ), migrations.AddField( model_name='tboffer', name='k_offer_to_source', field=models.ForeignKey(default=None, help_text='Обязательно - каждый оффер должен иметь источник. Через источник получаем данные продавца: offer.k_offer_to_source.k_source_to_seller', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='source_to_offer', to='frontend.tbsource', verbose_name='Источник данных'), ), migrations.AddIndex( model_name='tbarticle', index=models.Index(fields=['l_article_type', 'b_article_published', '-t_article_created'], name='idx_articles_by_type_published'), ), migrations.AddIndex( model_name='tbofferhistory', index=models.Index(fields=['k_history_to_offer', '-t_history_created'], name='idx_history_by_offer_date'), ), migrations.AddIndex( model_name='tboffer', index=models.Index(fields=['k_offer_to_item', '-f_offer_price'], name='idx_offer_by_item_price'), ), migrations.AddIndex( model_name='tboffer', index=models.Index(fields=['k_offer_to_item', 'i_offer_quantity'], name='idx_offer_by_item_qty'), ), ]