我有一些相互关联的python类,它们试图模仿graphql模式(模式本身不相关,我在这里发布了基本案例以重现问题)。
GraphQL 架构如下所示:
type User {
name: String
orders: [Order]
}
type Order {
key: String
user: User
}
从模式设计的角度来看,这个模式没有任何问题,它是一个有效的模式,并且我已经有一个使用这种关系运行的数据库(它只是意味着:一个用户可能有多个订单,一个订单可能只有一个用户创造了它)。
在 python 方面,事情变得有点混乱。
我希望以下代码能够工作:
文件:模型/模型.py
import attr
@attr.s
class Model():
pass # Model internal workings not relevant to the example
文件:模型/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)
文件:模型/Order.py
import attr
from . import Model
@attr.s
class Order(Model):
key: str = 'abc'
user: User = attr.ib(factory=User)
然后我可以做这样的事情:
文件:主.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'))
这个解决方案有效,但失去了事先知道字段类型的能力,而且我认为在构建复杂关系时它会更慢(数百个项目,对象有几个层次)。
这就是为什么我正在寻找更好的方法来解决这个问题,有什么想法吗?