mod: модели (preliminary 04) + миграции
А) Удалена таблица TbFormat (форматы носителей) и заменена на CharField в TbOffer. Б) Удалено поле s_img_copyright из модел TbImage (для этого будет использовано поле author из filer).
This commit is contained in:
@@ -9,7 +9,7 @@ from django.utils.html import format_html, mark_safe
|
||||
from easy_thumbnails.files import get_thumbnailer
|
||||
from .models import (
|
||||
TbImage, TbArticle, TbArtist, TbItem, TbLabel, TbSeller,
|
||||
TbOffer, TbSource, TbOfferHistory, TbMusicStyle, TbFormat
|
||||
TbOffer, TbSource, TbOfferHistory, TbMusicStyle
|
||||
)
|
||||
|
||||
# ============================================================================
|
||||
@@ -283,12 +283,6 @@ class MusicStyleAdmin(admin.ModelAdmin):
|
||||
readonly_fields = ('s_style_slug',)
|
||||
|
||||
|
||||
class FormatAdmin(admin.ModelAdmin):
|
||||
"""Админ для форматов"""
|
||||
list_display = ('id', 's_format', 's_format_slug')
|
||||
search_fields = ('s_format',)
|
||||
readonly_fields = ('s_format_slug',)
|
||||
|
||||
|
||||
class ArtistAdmin(admin.ModelAdmin):
|
||||
"""Админ для артистов"""
|
||||
@@ -332,9 +326,9 @@ class SourceAdmin(admin.ModelAdmin):
|
||||
class OfferAdmin(admin.ModelAdmin):
|
||||
"""Админ для предложений"""
|
||||
list_display = ('id', 's_offer', 'k_offer_to_item', 'f_offer_price', 'i_offer_quantity', 'i_offer_views')
|
||||
list_filter = ('l_offer_condition_media', 'l_offer_condition_sleeve', 't_offer_created')
|
||||
list_filter = ('l_offer_condition_media', 'l_offer_condition_sleeve', 't_offer_created', 'l_offer_to_format')
|
||||
search_fields = ('s_offer',)
|
||||
filter_horizontal = ('k_offer_to_format', 'k_offer_to_image')
|
||||
filter_horizontal = ('k_offer_to_image',)
|
||||
readonly_fields = ('s_offer_skip32', 't_offer_created', 't_offer_updated', 'i_offer_views', 'i_offer_favorites')
|
||||
|
||||
|
||||
@@ -351,7 +345,6 @@ class OfferHistoryAdmin(admin.ModelAdmin):
|
||||
admin.site.register(TbImage, ImageAdmin)
|
||||
admin.site.register(TbArticle, ArticleAdmin)
|
||||
admin.site.register(TbMusicStyle, MusicStyleAdmin)
|
||||
admin.site.register(TbFormat, FormatAdmin)
|
||||
admin.site.register(TbArtist, ArtistAdmin)
|
||||
admin.site.register(TbItem, ItemAdmin)
|
||||
admin.site.register(TbLabel, LabelAdmin)
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
# Generated by Django 6.0.5 on 2026-06-12 10:39
|
||||
|
||||
import django.db.models.deletion
|
||||
import filer.fields.image
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('frontend', '0001_initial'),
|
||||
migrations.swappable_dependency(settings.FILER_IMAGE_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='tboffer',
|
||||
name='k_offer_to_format',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='tbimage',
|
||||
name='s_img_copyright',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='tboffer',
|
||||
name='l_offer_to_format',
|
||||
field=models.CharField(choices=[('lp', 'Vinyl Long-Play (12")'), ('ep', 'Vinyl Extended-Play (12", 10", 7")'), ('45', 'Vinyl 7" (45 rpm)'), ('cd', 'Compact Disc'), ('ld', 'LaserDisc'), ('md', 'MiniDisc Record'), ('ms', 'Used MiniDisc (для записи)'), ('cs', 'Cassette Record'), ('uc', 'Used Cassette (для записи)'), ('tp', 'Tape Reel Record'), ('ur', 'Used Tape Reel (для записи)'), ('??', 'Other')], db_index=True, default='??', help_text='Форматы основного носителей (пластинка, CD, кассета и т.п.). Если несколько носителей (и разных), то это указывать в "Дополнительных данных" в JSON-формате. Например: <tt>{"formats": {"lp": 2, "cd": 1},}</tt>', max_length=2, verbose_name='Формат'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='tbimage',
|
||||
name='f_img_confidence_score',
|
||||
field=models.FloatField(blank=True, default=10.0, help_text='Уверенность (для автоматических данных) 0.0 - 10.0, насколько уверены, что это правильное изображение', null=True, verbose_name='Достоверность'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='tbimage',
|
||||
name='i_img_sort',
|
||||
field=models.IntegerField(db_index=True, default=0, help_text='Порядок отображения изображений. Чем меньше число, тем выше в списке. Можно использовать для указания обложки (0), задника (1) и т.д.', verbose_name='Сортировка'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='tbimage',
|
||||
name='image',
|
||||
field=filer.fields.image.FilerImageField(default=1, help_text='Файл изображения, загруженный через django_filer.', on_delete=django.db.models.deletion.DO_NOTHING, to=settings.FILER_IMAGE_MODEL, verbose_name='Файл изображения'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='tbimage',
|
||||
name='s_img_src_url',
|
||||
field=models.URLField(blank=True, help_text='URL источника, если изображение взято (в том числе и парсером) из внешнего источника (например, Discogs)', null=True, verbose_name='URL'),
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='TbFormat',
|
||||
),
|
||||
]
|
||||
@@ -28,7 +28,6 @@
|
||||
# │ l_img_reality │ Тип (real, abstract)
|
||||
# │ i_img_sort │ Порядок отображения
|
||||
# │ f_img_confidence_ │ Доверие данным (0-1)
|
||||
# │ s_img_copyright │ Авторские права
|
||||
# │ t_img_created │ Timestamp
|
||||
# │ t_img_updated │ Timestamp
|
||||
# │ │ ⬆ Индекс на: id (+), i_img_sort
|
||||
@@ -95,16 +94,6 @@
|
||||
# │ [промежуточная таблица: article_id, musicstyle_id]
|
||||
#
|
||||
#
|
||||
# ┌──────────────────┐
|
||||
# │ TbFormat │ Форматы носителей (LP, CD, Cassette...)
|
||||
# ├──────────────────┼────────────────────────────────────────────────────────
|
||||
# │ PK: id │ AutoField
|
||||
# │ s_format │ Название (LP, CD, Blu-ray, Cassette...)
|
||||
# │ s_format_slug │ SlugField(16) — уникальный
|
||||
# └──────────────────┘
|
||||
# △
|
||||
# │ M2M TbOffer.k_offer_to_format
|
||||
# │ [промежуточная таблица: offer_id, format_id]
|
||||
#
|
||||
#
|
||||
# ##════════════════════════════════════════════════════════════════════════════##
|
||||
@@ -148,11 +137,11 @@
|
||||
# ├────────────────────────────────┼───────────────────────────────
|
||||
# │ PK: id │ AutoField
|
||||
# │ s_offer │ Название (indexed)
|
||||
# │ l_offer_to_format │ Формат (CD, Vinyl, Digital...)
|
||||
# │ k_offer_to_item │ FK → TbItem [indexed]
|
||||
# │ k_offer_to_label │ FK → TbLabel [indexed]
|
||||
# │ k_offer_to_source │ FK → TbSource [indexed]
|
||||
# │ k_offer_to_article │ FK → TbArticle (опционально)
|
||||
# │ k_offer_to_format │ M2M → TbFormat (может быть несколько)
|
||||
# │ k_offer_to_image │ M2M → TbImage (несколько фото)
|
||||
# │ l_offer_condition_media │ Состояние (s, m, nm, vg, g, f, p)
|
||||
# │ l_offer_condition_sleeve │ Состояние (s, m, nm, vg, g, f, p)
|
||||
@@ -318,15 +307,6 @@ class TbImage(models.Model):
|
||||
verbose_name='Достоверность',
|
||||
help_text='Уверенность (для автоматических данных) 0.0 - 10.0, насколько уверены, что это правильное изображение',
|
||||
)
|
||||
s_img_copyright = models.CharField(
|
||||
# Авторские права и лицензия (по идее -- ненужное поле. Можно в filer использовать `obj.image.author`.
|
||||
max_length=255,
|
||||
blank=True,
|
||||
default='',
|
||||
editable=False, # Поле не редактируется. Кандидат на удаление.
|
||||
verbose_name='Авторские права / Лицензия',
|
||||
help_text='Например: "© 2024 User" или "CC-BY"',
|
||||
)
|
||||
t_img_created = models.DateTimeField(auto_now_add=True, verbose_name='Дата добавления',)
|
||||
t_img_updated = models.DateTimeField(auto_now=True, verbose_name='Дата обновления',)
|
||||
|
||||
@@ -824,43 +804,6 @@ class TbSeller(models.Model):
|
||||
ordering = ('s_seller',)
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# ФОРМАТЫ НОСИТЕЛЕЙ
|
||||
# ============================================================================
|
||||
class TbFormat(models.Model):
|
||||
"""
|
||||
Формат носителя (LP, CD, Cassette и т.д.).
|
||||
|
||||
Используем SmallAutoField для оптимизации (макс ~32k).
|
||||
Форматов обычно 50-100, поэтому 2 байта более чем достаточно.
|
||||
"""
|
||||
# Используем SmallAutoField для оптимизации
|
||||
id = models.SmallAutoField(primary_key=True)
|
||||
s_format = models.CharField(
|
||||
max_length=16,
|
||||
blank=False,
|
||||
unique=True,
|
||||
db_index=True,
|
||||
verbose_name='Формат носителя',
|
||||
help_text='Название формата носителя, например: "LP", "CD", "Blu-ray", "Compact Cassette", "MiniDisc",'
|
||||
' "Hi-Fi", "Accessory" и т.д.',
|
||||
)
|
||||
s_format_slug = models.SlugField(
|
||||
max_length=16,
|
||||
blank=False,
|
||||
unique=True,
|
||||
verbose_name='Слаг',
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return f"format: {self.s_format}"
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Формат носителя'
|
||||
verbose_name_plural = 'Форматы носителей'
|
||||
ordering = ('s_format',)
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# ПРЕДЛОЖЕНИЯ / ОФФЕРЫ
|
||||
# ============================================================================
|
||||
@@ -879,6 +822,20 @@ class TbOffer(models.Model):
|
||||
P = 'p', 'Poor (плохое)'
|
||||
OTHER = '??', 'Other'
|
||||
|
||||
class Format(models.TextChoices):
|
||||
LP = 'lp', 'Vinyl Long-Play (12")'
|
||||
EP = 'ep', 'Vinyl Extended-Play (12", 10", 7")'
|
||||
V45 = '45', 'Vinyl 7" (45 rpm)'
|
||||
CD = 'cd', 'Compact Disc'
|
||||
LD = 'ld', 'LaserDisc'
|
||||
REC_MD = 'md', 'MiniDisc Record'
|
||||
USE_MD = 'ms', 'Used MiniDisc (для записи)'
|
||||
REC_CS = 'cs', 'Cassette Record'
|
||||
USE_CS = 'uc', 'Used Cassette (для записи)'
|
||||
REC_RR = 'tp', 'Tape Reel Record'
|
||||
USE_RR = 'ur', 'Used Tape Reel (для записи)'
|
||||
OTHER = '??', 'Other'
|
||||
|
||||
s_offer = models.CharField(
|
||||
max_length=128,
|
||||
blank=False,
|
||||
@@ -887,6 +844,16 @@ class TbOffer(models.Model):
|
||||
help_text='Техническое название оффера для внутреннего использования, например:'
|
||||
' "Abbey Road (LP) AnTrop NM/NM (МЗГ)" или "TDK CDing I 60 (б/у) VG/VG (Janan, 198x синяя-градиент)"'
|
||||
)
|
||||
l_offer_to_format = models.CharField(
|
||||
max_length=2,
|
||||
choices=Format.choices,
|
||||
default=Format.OTHER,
|
||||
db_index=True,
|
||||
verbose_name='Формат',
|
||||
help_text='Форматы основного носителей (пластинка, CD, кассета и т.п.). Если несколько носителей (и разных),'
|
||||
' то это указывать в "Дополнительных данных" в JSON-формате. Например:'
|
||||
' <tt>{"formats": {"lp": 2, "cd": 1},}</tt>',
|
||||
)
|
||||
# Связи
|
||||
k_offer_to_article = models.ForeignKey(
|
||||
TbArticle,
|
||||
@@ -950,14 +917,6 @@ class TbOffer(models.Model):
|
||||
verbose_name='Каталожный номер / Barcode',
|
||||
help_text='Например: "SD 16023" или "5099923452355"',
|
||||
)
|
||||
k_offer_to_format = models.ManyToManyField(
|
||||
TbFormat,
|
||||
blank=True,
|
||||
related_name='format_to_offer', # ← format.format_to_offers.all()
|
||||
db_index=True, # Принудительно создаем индекс, т.к. SQLite их сам не создаст.
|
||||
verbose_name='Форматы',
|
||||
help_text='Форматы носителей (пластинка, CD, кассета и т.п.). Можно выбрать несколько.',
|
||||
)
|
||||
d_offer_date_release = models.DateField(
|
||||
blank=True,
|
||||
null=True,
|
||||
|
||||
Reference in New Issue
Block a user