Django 1.7 - 模型发现和应用程序配置自定义应用程序标签

时间:2014-12-18 08:57:40

标签: python django django-1.7 django-migrations

我目前正在使用Django==1.7.1。我有一些具有相同模块名称的可重用应用程序。这也使得模型的应用标签相同。这实际上是矛盾的。您不能在INSTALLED_APPS文件的settings中的不同库中使用具有相同名称的模块。

我通过为模块添加AppConfig并更改了标签(app_label)以解决冲突来解决这个问题;

#librarayX.my_module.apps.py
from django.apps import AppConfig


class ModuleAppConfig(AppConfig):
    name = 'libraryX.my_module'
    label = "X_my_module"
    verbose_name = "my_module"



#librarayY.my_module.apps.py
from django.apps import AppConfig


class ModuleAppConfig(AppConfig):
    name = 'libraryY.my_module'
    label = "Y_my_module"
    verbose_name = "my_module"


#settings.py

....
INSTALLED_APPS=[
    ...
   'libraryX.my_module.apps.ModuleAppConfig',
   'libraryY.my_module.apps.ModuleAppConfig',
    ...
]
...

现在,我可以将这些应用配置添加到我的INSTALLED_APPS而不是模块中。冲突刚刚解决。到那时为止一切都还可以。

这是我的问题;当我覆盖AppConfig的标签时,Django不会发现该模块中的模型。我跑的时候;

python manage.py makemigrations

似乎没有任何改变。尽管我删除了所有迁移文件,但它甚至没有创建初始文件。我想,它没有看到模型。每当我从app app中删除重写的标签字段时,模型都可以再次被发现。所以,不要认为我的模型位置是错误的。

这也可能是错误,我不知道。但如果我做错了什么,它会是什么?

谢谢!

1 个答案:

答案 0 :(得分:3)

我深深地回顾了Django代码的大部分内容。应用程序配置中定义的自定义应用程序标签的应用程序中的模型(如问题中所示)不会由Django导入。这是因为,即使您在app config中更改标签,模型app_label也不会更改。所以,Django认为,模型和自定义应用程序配置是针对不同的应用程序。我想,这是一个错误

django.apps.registry中,populate method中的行是:

...
            # Load models.
            for app_config in self.app_configs.values():
                all_models = self.all_models[app_config.label]
                app_config.import_models(all_models)
...

此部分还应导入app_config.name中定义的模块中的模型,而不仅仅是app_config.label。因为,应用程序标签与应用程序配置标签不同的模型。这是引起问题的问题部分之一。这还不够,还需要以某种方式更改模型app_label

解决方案:

这是我的解决方法。

我有一个抽象的应用程序配置,我的所有app配置都将继承。

from collections import OrderedDict
from django.apps import AppConfig, apps


class BaseAppConfig(AppConfig):
    def __init__(self, *args, **kwargs):
        super(BaseAppConfig, self).__init__(*args, **kwargs)
        # Also import the models in modules defined in self.name
        mod_path, _, cls_name = self.name.rpartition('.')
        self.import_models(OrderedDict([(k, v) for k, v in apps.all_models[cls_name].iteritems() if self.name in v.__module__]))


    def import_models(self, all_models):
        if not self.models:
            # Set the model app_labels as self.label
            for m in all_models.values():
                m._meta.app_label = self.label
            super(BaseAppConfig, self).import_models(all_models)

这是一种不触及Django代码的解决方法。但是,我认为这个问题必须在Django中解决。模型app_labels也应该通过app config中定义的app_label值进行更改。