diff --git a/store/management/commands/create_initial_data.py b/store/management/commands/create_initial_data.py index da85069..d68f9b5 100644 --- a/store/management/commands/create_initial_data.py +++ b/store/management/commands/create_initial_data.py @@ -122,20 +122,22 @@ payment_methods = { } +def create_categories(): + for cat_name, subcat_names in tqdm(category_names.items(), desc="Creating categories"): + category, _ = Category.objects.get_or_create(name=cat_name, parent=None) + for subcat_name in subcat_names: + Category.objects.get_or_create(name=subcat_name, parent_id=category.id) + + +def create_payment_types(): + for slug, data in tqdm(payment_methods.items(), desc="Creating payment methods"): + PaymentMethod.objects.get_or_create(slug=slug, defaults=data) + + class Command(BaseCommand): help = ''' Create root categories ''' - def create_categories(self): - for cat_name, subcat_names in tqdm(category_names.items(), desc="Creating categories"): - category, _ = Category.objects.get_or_create(name=cat_name, parent=None) - for subcat_name in subcat_names: - Category.objects.get_or_create(name=subcat_name, parent_id=category.id) - - def create_payment_types(self): - for slug, data in tqdm(payment_methods.items(), desc="Creating payment methods"): - PaymentMethod.objects.get_or_create(slug=slug, defaults=data) - def handle(self, *args, **kwargs): - self.create_categories() - self.create_payment_types() + create_categories() + create_payment_types() diff --git a/store/migrations/0041_remove_category_slug_remove_checklist_subcategory_and_more.py b/store/migrations/0041_remove_category_slug_remove_checklist_subcategory_and_more.py new file mode 100644 index 0000000..18d2880 --- /dev/null +++ b/store/migrations/0041_remove_category_slug_remove_checklist_subcategory_and_more.py @@ -0,0 +1,134 @@ +# Generated by Django 4.2.2 on 2023-08-19 16:45 + +import datetime + +import django.core.validators +from django.conf import settings +from django.db import migrations, models, transaction +import django.db.models.deletion +import mptt.fields +from mptt import register, managers + +from store.management.commands.create_initial_data import create_categories + + +def create_initial_categories(apps, schema_editor): + create_categories() + + +# Dummy model with the removed field(s) +class OldChecklist(models.Model): + id = models.CharField(primary_key=True, max_length=settings.CHECKLIST_ID_LENGTH) + category_id = models.PositiveIntegerField() + subcategory = models.CharField('Подкатегория', max_length=20, blank=True, null=True) + + class Meta: + managed = False + db_table = 'store_checklist' + + +# Add mptt fields to Category +# Loop through orders, save subcategory names and category ids +# Create subcategories, link to parent category +# Loop through orders, if subcategory was present, set it as category +# Perform migration - remove subcategory field +def create_subcategories(apps, schema_editor): + Checklist = apps.get_model("store", "Checklist") + Category = apps.get_model("store", "Category") + + # Loop through orders, save subcategory names and category ids + # Create subcategories, link to parent category + # If Checklist had subcategory, set it as category + with transaction.atomic(): + for checklist in OldChecklist.objects.all(): + if checklist.subcategory is None or checklist.category_id is None: + continue + + category_data = {'name': checklist.subcategory, 'parent_id': checklist.category_id} + # just to overcome not-null constraint errors for mptt + mptt_data = {'level': 0, 'lft': 0, 'rght': 0, 'tree_id': 0} + + subcat_obj, _ = Category.objects.get_or_create(**category_data, defaults=mptt_data) + + # To really update the Checklist, we must use a real model instead of the dummy OldChecklist one + Checklist.objects.filter(id=checklist.id).update(category_id=subcat_obj.id) + + +def rebuild_tree(apps, schema_editor): + model = apps.get_model('store', 'Category') + + manager = managers.TreeManager() + manager.model = model + + register(model) + manager.contribute_to_class(model, 'objects') + manager.rebuild() + + +class Migration(migrations.Migration): + + dependencies = [ + ('store', '0040_alter_paymentmethod_cardnumber_and_more'), + ] + + operations = [ + migrations.RemoveField( + model_name='category', + name='slug', + ), + migrations.AddField( + model_name='category', + name='commission', + field=models.DecimalField(decimal_places=2, default=0, max_digits=10, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(100)], verbose_name='Дополнительная комиссия, %'), + ), + + migrations.AddField( + model_name='category', + name='level', + field=models.PositiveIntegerField(default=0, editable=False), + preserve_default=False, + ), + migrations.AddField( + model_name='category', + name='lft', + field=models.PositiveIntegerField(default=0, editable=False), + preserve_default=False, + ), + migrations.AddField( + model_name='category', + name='parent', + field=mptt.fields.TreeForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='children', to='store.category', verbose_name='Родительская категория'), + ), + migrations.AddField( + model_name='category', + name='rght', + field=models.PositiveIntegerField(default=0, editable=False), + preserve_default=False, + ), + migrations.AddField( + model_name='category', + name='tree_id', + field=models.PositiveIntegerField(db_index=True, default=0, editable=False), + preserve_default=False, + ), + + migrations.RunPython(code=create_initial_categories), + migrations.RunPython(code=create_subcategories), + migrations.RunPython(code=rebuild_tree), + + migrations.AddField( + model_name='globalsettings', + name='time_to_buy', + field=models.DurationField(default=datetime.timedelta(seconds=10800), help_text="Через N времени заказ переходит из статуса 'Новый' в 'Черновик'", verbose_name='Время на покупку'), + ), + migrations.AlterField( + model_name='promocode', + name='discount', + field=models.PositiveIntegerField(verbose_name='Скидка в рублях'), + ), + + migrations.RemoveField( + model_name='checklist', + name='subcategory', + ), + ] diff --git a/store/migrations/0041_remove_checklist_category_and_more.py b/store/migrations/0041_remove_checklist_category_and_more.py deleted file mode 100644 index 3c73c3b..0000000 --- a/store/migrations/0041_remove_checklist_category_and_more.py +++ /dev/null @@ -1,35 +0,0 @@ -# Generated by Django 4.2.2 on 2023-08-17 23:19 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('store', '0040_alter_paymentmethod_cardnumber_and_more'), - ] - - operations = [ - migrations.RemoveField( - model_name='checklist', - name='category', - ), - migrations.RemoveField( - model_name='checklist', - name='subcategory', - ), - migrations.AddField( - model_name='globalsettings', - name='time_to_buy', - field=models.DurationField(default=datetime.timedelta(seconds=10800), help_text="Через N времени заказ переходит из статуса 'Новый' в 'Черновик'", verbose_name='Время на покупку'), - ), - migrations.AlterField( - model_name='promocode', - name='discount', - field=models.PositiveIntegerField(verbose_name='Скидка в рублях'), - ), - migrations.DeleteModel( - name='Category', - ), - ] diff --git a/store/migrations/0042_category_checklist_category.py b/store/migrations/0042_category_checklist_category.py deleted file mode 100644 index 40542a6..0000000 --- a/store/migrations/0042_category_checklist_category.py +++ /dev/null @@ -1,39 +0,0 @@ -# Generated by Django 4.2.2 on 2023-08-17 23:20 - -import django.core.validators -from django.db import migrations, models -import django.db.models.deletion -import mptt.fields - - -class Migration(migrations.Migration): - - dependencies = [ - ('store', '0041_remove_checklist_category_and_more'), - ] - - operations = [ - migrations.CreateModel( - name='Category', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=20, verbose_name='Название')), - ('delivery_price_CN_RU', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='Цена доставки Китай-РФ')), - ('commission', models.DecimalField(decimal_places=2, default=0, max_digits=10, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(100)], verbose_name='Дополнительная комиссия, %')), - ('lft', models.PositiveIntegerField(editable=False)), - ('rght', models.PositiveIntegerField(editable=False)), - ('tree_id', models.PositiveIntegerField(db_index=True, editable=False)), - ('level', models.PositiveIntegerField(editable=False)), - ('parent', mptt.fields.TreeForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='children', to='store.category', verbose_name='Родительская категория')), - ], - options={ - 'verbose_name': 'Категория', - 'verbose_name_plural': 'Категории', - }, - ), - migrations.AddField( - model_name='checklist', - name='category', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='store.category', verbose_name='Категория'), - ), - ]