避免在 Django 模型中循环导入 (Config class)
Avoiding circular imports in Django Models (Config class)
我在 Django 中创建了一个配置模型,以便站点管理员可以即时更改一些设置,但是一些模型依赖于这些配置。我正在使用 Django 2.0.2 和 Python 3.6.4.
我在与 models.py 相同的目录中创建了一个 config.py 文件。
Let me paracode(parapase 代码?Real Enum 有更多选项):
# models.py
from .config import *
class Configuration(models.Model):
starting_money = models.IntegerField(default=1000)
class Person(models.Model):
funds = models.IntegarField(default=getConfig(ConfigData.STARTING_MONEY))
# config.py
from .models import Configuration
class ConfigData(Enum):
STARTING_MONEY = 1
def getConfig(data):
if not isinstance(data, ConfigData):
raise TypeError(f"{data} is not a valid configuration type")
try:
config = Configuration.objects.get_or_create()
except Configuration.MultipleObjectsReturned:
# Cleans database in case multiple configurations exist.
Configuration.objects.exclude(Configuration.objects.first()).delete()
return getConfig(data)
if data is ConfigData.MAXIMUM_STAKE:
return config.max_stake
如何在不出现导入错误的情况下执行此操作?我试过绝对导入
您可以 推迟 加载 models.py
,方法是在 getConfig(data)
函数中加载它,因此我们在加载 config.py
:
时不再需要 models.py
# config.py (no import in the head)
class ConfigData(Enum):
STARTING_MONEY = 1
def getConfig(data):
<b>from .models import Configuration</b>
if not isinstance(data, ConfigData):
raise TypeError(f"{data} is not a valid configuration type")
try:
config = Configuration.objects.get_or_create()
except Configuration.MultipleObjectsReturned:
# Cleans database in case multiple configurations exist.
Configuration.objects.exclude(Configuration.objects.first()).delete()
return getConfig(data)
if data is ConfigData.MAXIMUM_STAKE:
return config.max_stake
因此我们不在config.py
中加载models.py
。我们仅在实际 执行 getConfig
函数时才检查它是否已加载(如果未加载则加载),该函数稍后在过程中。
Willem Van Onsem 的解决方案很好。我有一种不同的方法,我使用 django's Applications registry 将其用于循环模型依赖项。我 post 将其作为替代解决方案,部分原因是我希望更有经验的 python 编码人员就此方法是否存在问题提供反馈。
在实用程序模块中,定义以下方法:
from django.apps import apps as django_apps
def model_by_name(app_name, model_name):
return django_apps.get_app_config(app_name).get_model(model_name)
然后在您的 getConfig 中,省略导入并替换行
config = Configuration.objects.get_or_create()
具有以下内容:
config_class = model_by_name(APP_NAME, 'Configuration')
config = config_class.objects.get_or_create()
我在 Django 中创建了一个配置模型,以便站点管理员可以即时更改一些设置,但是一些模型依赖于这些配置。我正在使用 Django 2.0.2 和 Python 3.6.4.
我在与 models.py 相同的目录中创建了一个 config.py 文件。
Let me paracode(parapase 代码?Real Enum 有更多选项):
# models.py
from .config import *
class Configuration(models.Model):
starting_money = models.IntegerField(default=1000)
class Person(models.Model):
funds = models.IntegarField(default=getConfig(ConfigData.STARTING_MONEY))
# config.py
from .models import Configuration
class ConfigData(Enum):
STARTING_MONEY = 1
def getConfig(data):
if not isinstance(data, ConfigData):
raise TypeError(f"{data} is not a valid configuration type")
try:
config = Configuration.objects.get_or_create()
except Configuration.MultipleObjectsReturned:
# Cleans database in case multiple configurations exist.
Configuration.objects.exclude(Configuration.objects.first()).delete()
return getConfig(data)
if data is ConfigData.MAXIMUM_STAKE:
return config.max_stake
如何在不出现导入错误的情况下执行此操作?我试过绝对导入
您可以 推迟 加载 models.py
,方法是在 getConfig(data)
函数中加载它,因此我们在加载 config.py
:
models.py
# config.py (no import in the head)
class ConfigData(Enum):
STARTING_MONEY = 1
def getConfig(data):
<b>from .models import Configuration</b>
if not isinstance(data, ConfigData):
raise TypeError(f"{data} is not a valid configuration type")
try:
config = Configuration.objects.get_or_create()
except Configuration.MultipleObjectsReturned:
# Cleans database in case multiple configurations exist.
Configuration.objects.exclude(Configuration.objects.first()).delete()
return getConfig(data)
if data is ConfigData.MAXIMUM_STAKE:
return config.max_stake
因此我们不在config.py
中加载models.py
。我们仅在实际 执行 getConfig
函数时才检查它是否已加载(如果未加载则加载),该函数稍后在过程中。
Willem Van Onsem 的解决方案很好。我有一种不同的方法,我使用 django's Applications registry 将其用于循环模型依赖项。我 post 将其作为替代解决方案,部分原因是我希望更有经验的 python 编码人员就此方法是否存在问题提供反馈。
在实用程序模块中,定义以下方法:
from django.apps import apps as django_apps
def model_by_name(app_name, model_name):
return django_apps.get_app_config(app_name).get_model(model_name)
然后在您的 getConfig 中,省略导入并替换行
config = Configuration.objects.get_or_create()
具有以下内容:
config_class = model_by_name(APP_NAME, 'Configuration')
config = config_class.objects.get_or_create()