У меня есть несколько python классов, которые связаны друг с другом, они пытаются имитировать c схему graphql (Сама схема не имеет отношения, я выкладываю здесь базовый вариант для воспроизведения проблемы).
Схема GraphQL выглядит следующим образом:
type User {
name: String
orders: [Order]
}
type Order {
key: String
user: User
}
С точки зрения схемы, в этой схеме нет ничего плохого, она действительна, и у меня уже есть база данных, работающая с этими отношениями ( это просто означает: у пользователя может быть несколько заказов, у заказа может быть только один пользователь, который его создал).
Это в сторону python вещей, которые становятся немного грязными.
Я ожидаю, что следующий код будет работать:
файл: models / Model.py
import attr
@attr.s
class Model():
pass # Model internal workings not relevant to the example
файл: models / User.py
from typing import List
import attr
from . import Model
@attr.s
class User(Model):
name: str = 'Name'
orders: List[Order] = attr.ib(factory=list)
файл: models / Order.py
import attr
from . import Model
@attr.s
class Order(Model):
key: str = 'abc'
user: User = attr.ib(factory=User)
тогда я могу сделать что-то вроде этого:
file: main .py
import models as m
user = m.User.query(name='John', with='orders')
user.name # "John"
user.orders # [m.Order(key='1'), m.Order(key='2'), m.Order(key='3')...]
order = m.Order.query(key='1', with='user')
order.key # "1"
order.user # m.User(name="John")
Этот код не работает из-за циклической зависимости (пользователю требуется тип заказа, который должен быть определен ранее, а заказу требуется пользователь).
Обходной путь, который я обнаружил, заключался в позднем импорте моделей с использованием importlib:
# current solution:
# using the importlib to import dynamically
from typing import List
import attr
from helpers import convert_to, list_convert_to,
# Note: "convert_to" receives a class name and returns a function to instantiate it dinamically
@attr.s
class Model():
pass
@attr.s
class User(Model):
name: str = 'Name'
orders: List[Model] = attr.ib(factory=list_convert_to('Order'))
@attr.s
class Order(Model):
key: str = 'abc'
user: Model = attr.ib(factory=list_convert_to('User'))
Это решение работает, но теряет возможность заранее знать типы полей, и я думаю, что это медленнее при построении сложных отношений (сотни предметов с объектами глубиной в несколько уровней).
Вот почему я ищу лучшие способы решения этой проблемы, есть идеи?