gault-millau/apps/transfer/utils.py
2019-10-11 10:45:49 +03:00

162 lines
5.7 KiB
Python

from os.path import exists
from importlib.machinery import SourceFileLoader
from django.apps import apps
from collections import OrderedDict
from django.db.models import OuterRef, Subquery
import transfer.models as legacy_models
# from pprint import pprint as print
def transfer_objects(data_type):
models_list = {}
for app in apps.get_app_configs():
if exists(f"{app.path}/transfer.py"):
card_module = SourceFileLoader("transfer", f"{app.path}/transfer.py").load_module()
if not hasattr(card_module, "card") or len(card_module.card) < 1:
continue
for model, card in card_module.card.items():
if "data_type" in card and data_type == card["data_type"]:
card['app_label'] = app.label
models_list[model] = card
if len(models_list) < 1:
print(f"Models with data type {data_type} not found in structure")
exit(1)
models_list = sort_by_dependencies(models_list)
legacy_objects = OrderedDict()
for model, card in models_list.items():
legacy_objects[model] = get_model_data(model, card)
def sort_by_dependencies(data):
"""Сортировка моделей по зависимостям"""
"""Сначала мы сортируем модели по зависимостям в обратном порядке, используя сортировку вставкой"""
result = []
for model, card in data.items():
if "dependencies" in card and isinstance(card['dependencies'], tuple):
for model_dependency in result:
if model_dependency in card['dependencies']:
result.insert(result.index(model_dependency), model)
break
else:
result.append(model)
"""Затем мы создаём сортированный словарь из реверса получившегося результата"""
result = OrderedDict(
[(model, data[model]) for model in reversed(result)]
)
return result
def get_model_data(model, card):
# print(f"=================================================\r\n"
# f"MODEL: {model}\r\n"
# f"=================================================")
card_fields = card['fields']
relations = card_fields['relations'] if 'relations' in card_fields else None
if relations:
del(card_fields['relations'])
if len(card_fields) > 1:
print("You must set one table to transfer")
return
legacy_table = list(card_fields.keys())[0]
fields = list(card_fields.values())[0]
try:
legacy_model = apps.get_model(app_label="transfer", model_name=legacy_table)
except LookupError as e:
print(f"ERROR: legacy model {model} can not be loaded: {e}")
return
legacy_fields = []
for legacy_field in fields.values():
if isinstance(legacy_field, str):
legacy_fields.append(legacy_field)
elif isinstance(legacy_field, tuple):
if isinstance(legacy_field[0], tuple):
"""Группа полей"""
for legacy_field_group in legacy_field:
legacy_fields.append(legacy_field_group[1])
else:
"""Одиночное поле"""
legacy_fields.append(legacy_field[1])
#TODO: убрать после совместимости
if model != "City":
return
queryset = legacy_model.objects.only(*legacy_fields)
"""Проверяем наличие внешних связей"""
if relations:
queryset = get_relation_data(relations, queryset, fields)
return get_transfer_data(model, card, queryset)
def get_relation_data(relations, queryset, fields):
# related_legacy_models = [x.related_model._meta.model.__name__ for x in legacy_model._meta.related_objects]
"""Получаем названия внешних зависимостей"""
for relation_table, relation_data in relations.items():
"""Если объекты связаны через ForeignKey, то ничего не надо делать - все аннотации уже подключены"""
if isinstance(relation_data['key'], tuple):
"""Вытаскиваем relation по id"""
try:
child_legacy_model = apps.get_model(app_label="transfer", model_name=relation_table)
except LookupError as e:
raise LookupError(f"ERROR: legacy model {relation_table} can not be loaded: {e}")
child_table_queryset = child_legacy_model.objects.filter(
city_id=OuterRef('pk')
).only(*relation_data['fields'].values())
queryset = queryset.annotate(**{
f"{relation_table.lower()}":
Subquery(child_table_queryset)
})
return queryset
def get_transfer_data(model, card, queryset):
from pprint import pprint as print
try:
app_model = apps.get_model(app_label=card['app_label'], model_name=model)
except LookupError as e:
print(f"ERROR: model {model} from {card['app_label']} can not be loaded: {e}")
return
if "fields" not in card or not isinstance(card['fields'], dict) or len(card['fields']) != 1:
raise ValueError("You must set correct fields to transfer")
for app_field, legacy_field_data in card['fields'].items():
print(app_field)
print(legacy_field_data)
print("*************************************************************************")
# print(app_model)
# print("*************************************************************************")
# print(queryset)
return queryset