fidals / stroyprombeton

3 stars 1 forks source link

Fix the wrong models hierarhy at the DB #695

Closed duker33 closed 5 years ago

duker33 commented 5 years ago

Take the wrong products and categories from the script from comment and fix them automatically or manually https://github.com/fidals/stroyprombeton/issues/691#issuecomment-503016706

duker33 commented 5 years ago

it's the version to fix the DB structure

import typing

from stroyprombeton.models import Product, Category
from pages.models import Page

from contextlib import contextmanager
from django.db import transaction

@contextmanager
def non_persistence():
    with transaction.atomic():
        point = transaction.savepoint()
        yield
        transaction.savepoint_rollback(point)

def get_bad_products():
    bad_products = []
    for p in Product.objects.all():
        pages = p.page.get_ancestors(include_self=False).values_list('id', flat=True)[1:]
        categories = p.category.get_ancestors(include_self=True)
        categories_list = [c.page.id for c in categories]
        if not all(p == c for p, c in zip(pages, categories_list)):
            bad_products.append(p)
    return bad_products

def get_bad_categories():
    bad_categories = []
    bad_pairs = []
    for c in Category.objects.all():
        pages = c.page.get_ancestors(include_self=True).values_list('id', flat=True)[1:]
        categories = c.get_ancestors(include_self=True)
        categories_list = [c.page.id for c in categories]
        if not all(p == c for p, c in zip(pages, categories_list)):
            bad_categories.append(c)
            bad_pairs.append((pages, categories_list))
    # print('\n---\n'.join(['\n'.join([p, c]) for p, c in bad_pairs[:20]]))
    return bad_categories

def fix_ancestors(category: Category):
    ancestors = category.get_ancestors(ascending=True, include_self=True)
    for cur, next in zip(ancestors, ancestors[1:]):
        cur.page.parent = next.page
        cur.page.save()

def fix_categories(bad_categories: typing.List[Category]):
    for category in Category.objects.filter(id__in=[c.id for c in bad_categories]):
        fix_ancestors(category)

def fix_products(bad_products: typing.List[Product]):
    for product in Product.objects.filter(id__in=[p.id for p in bad_products]):
        product.page.parent = product.category.page
        product.page.save()
        fix_ancestors(product.category)

with non_persistence():
    bad_categories = get_bad_categories()
    bad_products = get_bad_products()
    print(f'bad categories before: {len(bad_categories)}')
    print(f'bad products before: {len(bad_products)}')
    fix_categories(bad_categories)
    fix_products(bad_products)
    Page.objects.rebuild()
    print(f'bad categories after: {len(get_bad_categories())}')
    print(f'bad products after: {len(get_bad_products())}')
duker33 commented 5 years ago

It's output. Seems all is correct

bad categories after: 14
bad products after: 19
bad categories before: 0
bad products before: 0