【问题标题】:Django get list of models in applicationDjango 获取应用程序中的模型列表
【发布时间】:2012-01-31 22:22:25
【问题描述】:

所以,我在 MyApp 文件夹中有一个文件 models.py:

from django.db import models
class Model_One(models.Model):
    ...
class Model_Two(models.Model):
    ...
...

大约有 10-15 节课。 如何在 MyApp 中找到所有模型并获取它们的名称?

由于模型不可迭代,我不知道这是否可能。

【问题讨论】:

  • @downvoter,想分享你投反对票的原因吗?这个问题没有错(+1 平衡)
  • 我不同意反对票。如果您想在运行时了解模型,则 Grep 不适合。 get_app 和 get_models 在这种情况下是完美的。
  • “在运行时知道模型”?这是什么意思?
  • @S.Lott 这可能不是最好的选择。如果我想在视图中迭代应用程序的模型,我认为最好使用get_appget_models 函数,而不是获取源代码并硬编码需要维护的列表。
  • 好的,语法先生。这是“你”的简短版本,每个说英语的人都能读懂。但我以后会采纳你的建议

标签: python django model


【解决方案1】:

更新

对于较新版本的 Django,请查看 Sjoerd 答案

2012 年的原始答案: 这是完成您想做的事情的最佳方式:

from django.db.models import get_app, get_models

app = get_app('my_application_name')
for model in get_models(app):
    # do something with the model

在这个例子中,model 是实际模型,所以你可以用它做很多事情:

for model in get_models(app):
    new_object = model() # Create an instance of that model
    model.objects.filter(...) # Query the objects of that model
    model._meta.db_table # Get the name of the model in the database
    model._meta.verbose_name # Get a verbose name of the model
    # ...

【讨论】:

  • 从 django 1.7 开始,您应该使用新的应用程序加载系统:from django.apps import apps 包含这些方法。 django.db.models.loading 将在 django 1.9 中删除。
  • 我仍在使用 django 1.6.x,所以这个答案对我很有用。问题:给定一个来自 get_models 的模型,如何获得可以随后传递给 get_model(app_name, model_name) 的名称?我需要这个,因为我想在一个地方以字符串形式获取所有模型名称的列表,并将名称传递给另一段代码,然后调用 get_model。
【解决方案2】:

从 Django 1.7 开始,您可以使用此代码,例如在您的 admin.py 中注册所有模型:

from django.apps import apps
from django.contrib import admin
from django.contrib.admin.sites import AlreadyRegistered

app_models = apps.get_app_config('my_app').get_models()
for model in app_models:
    try:
        admin.site.register(model)
    except AlreadyRegistered:
        pass

【讨论】:

  • 不适用于 django v2+。
【解决方案3】:

另一种方法是使用Content Types

INSTALLED_APPS 中每个应用程序的每个模型在 ContentType 模型中都有一个条目。例如,这允许您拥有模型的外键。

>>> from django.contrib.contenttypes.models import ContentType
>>> ContentType.objects.filter(app_label="auth")
<QuerySet [<ContentType: group>, <ContentType: permission>, <ContentType: user>]>
>>> [ct.model_class() for ct in ContentType.objects.filter(app_label="auth")]
[<class 'django.contrib.auth.models.Group'>, <class 'django.contrib.auth.models.Permission'>, <class 'django.contrib.auth.models.User'>]

【讨论】:

    【解决方案4】:

    我找到的从应用中获取所有模型的最佳答案:

    from django.apps import apps
    apps.all_models['<app_name>']  #returns dict with all models you defined
    

    【讨论】:

    • 如果您需要打印它,请使用dict(apps.all_models['&lt;app_name&gt;']),否则您会收到OrderedDict() 作为响应。
    • @GiampaoloFerradini - 我得到了一个类似{'materials': &lt;class 'logis.models.Materials'&gt;, ...} 的列表。如何从列表中仅获取模型名称(例如,Materials)?
    • @user12379095 你做了类似的事情,例如for k in m_d: print(k) 其中m_d 是您的应用模型字典,您将其定义为`m_d = dict(apps.all_models['your_app_name']
    • @user12379095 如果您需要包括大写在内的确切型号字段,您可以使用for k in m_d: print(m_d[k].__name__)(其余代码保持不变)
    • @GiampaoloFerradini - 谢谢。我解决它的方法是从列表中创建一个熊猫数据框,然后显示为 html。再次感谢。
    【解决方案5】:

    这是一个使用dumpdatajq 的快速而简单的无编码解决方案:

    python manage.py dumpdata oauth2_provider | jq -r '.[] | .model' | uniq
    

    您还可以清理 jq 命令以获得您喜欢的格式。


    奖励:您可以通过将-c 标志添加到uniq 来查看不同类型对象的计数。

    【解决方案6】:

    我来到这里是因为我想为每个应用自动提取灯具。

    这会打印出用于转储项目中所有对象的固定装置的命令。 (我已将我的应用程序移至 apps 目录中。)

    from django.apps import apps
    from django.conf import settings
    
    print(
        '\n'.join(
            [
                '\n'.join(
                    [
                        f'PYTHONPATH=.:apps django-admin dumpdata {app}.{model} --settings=my_project.settings > apps/{app}/fixtures/{model}.json'
                        for model in apps.all_models[app]
                    ]
                )
                for app in settings.INSTALLED_APPS
            ]
        )
    )
    

    检查您是否已激活您的虚拟环境,以便您使用正确的django-admin。 (与which django-admin.py联系。)

    仅与原始问题无关,但可能对出于与我相同的原因偶然发现此问题的人有用。我在 Django 2.2.4 上,没有在其他地方测试过。

    【讨论】:

    • 如果您指出您需要它的原因与原始问题不同,这可能会有所帮助。另外,您不能只使用from django.conf import settings,然后在settings.INSTALLED_APPS 上进行迭代,而不必“从设置文件中复制您的应用列表”吗?
    【解决方案7】:

    对于我自己偶然发现这个问题的用例,我正在寻找模型来自哪个应用程序(用于数据库路由器检查以及是否允许关系,以防不同数据库具有相同模型名称)。

    就我而言,事实证明每个模型都有一个元标记,表明它来自哪个应用程序。这可能对处于相同情况的其他人有所帮助。

    例如,如果向函数传递模型 model,则定义该模型的应用程序会在 model._meta.app_label 中作为字符串找到。所以对于一个数据库路由器,你可以声明:

    def allow_relation(self, obj1, obj2, **hints):
        """Determine whether to allow ForeignKey relationships between two objects"""
        # if neither object is from MyApp, then this router doesn't care. 
        if 'MyApp' not in [obj1._meta.app_label, obj2._meta.app_label]:
            return None  # None means "no opinion" so other routers can still chime in
        else:
            # at least one object is from MyApp, so allow foreignkey relationships.
            return True
    

    【讨论】:

    • 直到很久以后我才知道跨数据库关系的局限性或完全无能为力,所以我最终放弃了这个想法的前提——但_meta.app_label 仍然可以在其他方面得心应手。
    【解决方案8】:

    在@GiampaoloFerradini 的一些谨慎输入下从@pedrotorres 解决方案中脱颖而出,这就是我最终使用的:

    from django.apps import apps
    
    app_models = [model.__name__ for model in apps.get_models()] # Returns a "list" of all models created
    

    【讨论】:

    • 干净的方式,@user12379095,但它适用于所有应用程序,而不是按照 OP 中的要求
    • 正是我所需要的。
    猜你喜欢
    • 2013-10-04
    • 2011-02-14
    • 2014-04-03
    • 2019-10-07
    • 2011-03-07
    • 1970-01-01
    • 2016-03-15
    • 2017-03-14
    • 2018-09-02
    相关资源
    最近更新 更多