【问题标题】:Django: Get model from string?Django:从字符串中获取模型?
【发布时间】:2011-06-20 09:03:24
【问题描述】:

在 Django 中,您可以指定如下关系:

author = ForeignKey('Person')

然后它必须在内部将字符串“Person”转换为模型Person

执行此操作的函数在哪里?我想用它,但我找不到它。

【问题讨论】:

    标签: django django-models


    【解决方案1】:

    从 Django 1.114.0(至少),它是 AppConfig.get_model(model_name, require_ready=True)

    从 Django 1.9 开始,该方法为 django.apps.AppConfig.get_model(model_name)
    -- danihp

    从 Django 1.7 开始,django.db.models.loading 已弃用(将在 1.9 中删除)以支持新的应用程序加载系统。
    -- Scott Woodall


    找到了。它在这里定义:

    from django.db.models.loading import get_model
    

    定义为:

    def get_model(self, app_label, model_name, seed_cache=True):
    

    【讨论】:

    • 此解决方案在 Django 1.7 中已弃用,请参阅此解决方案的其他答案:stackoverflow.com/a/26126935/155987
    • 嗨@mpen,我建议你更新你的答案。 On django 1.9 get_model is defined on AppConfig: from django.apps import AppConfig
    • 在 Django 1.7+ 中,最好在 Django 应用程序注册表上使用 get_model(),它可以通过 django.apps.apps.get_model(model_name) 获得。 AppConfig 对象有不同的用途,需要您创建一个 AppConfig 实例才能调用get_model()
    • Django 1.11 需要@luke_aus 提供的答案
    • 最新 (2020) 解决方案:from django.apps import apps 然后:apps.get_model('app_name', 'Model') stackoverflow.com/questions/38443628/…
    【解决方案2】:

    django.db.models.loadingdeprecated in Django 1.7 (removed in 1.9) 支持新的 application loading system

    Django 1.7 docs 改为给我们以下内容:

    >>> from django.apps import apps
    >>> User = apps.get_model(app_label='auth', model_name='User')
    >>> print(User)
    <class 'django.contrib.auth.models.User'>
    

    【讨论】:

    • 我曾经使用 pydoc 的“定位”功能...不确定这里的区别,但为了留在 Django 中,我已经切换到这种方法。谢谢。
    【解决方案3】:

    仅适用于任何被卡住的人(就像我一样):

    from django.apps import apps
    
    model = apps.get_model('app_name', 'model_name')
    

    app_name 应使用引号列出,model_name 也应使用引号(即不要尝试导入它)

    get_model 接受小写或大写 'model_name'

    【讨论】:

      【解决方案4】:

      大多数模型“字符串”以“appname.modelname”的形式出现,因此您可能希望在 get_model 上使用此变体

      from django.db.models.loading import get_model
      
      your_model = get_model ( *your_string.split('.',1) )
      

      django 代码中通常将此类字符串转换为模型的部分稍微复杂一些来自django/db/models/fields/related.py

          try:
              app_label, model_name = relation.split(".")
          except ValueError:
              # If we can't split, assume a model in current app
              app_label = cls._meta.app_label
              model_name = relation
          except AttributeError:
              # If it doesn't have a split it's actually a model class
              app_label = relation._meta.app_label
              model_name = relation._meta.object_name
      
      # Try to look up the related model, and if it's already loaded resolve the
      # string right away. If get_model returns None, it means that the related
      # model isn't loaded yet, so we need to pend the relation until the class
      # is prepared.
      model = get_model(app_label, model_name,
                        seed_cache=False, only_installed=False)
      

      对我来说,这似乎是一个很好的案例,可以将其拆分为核心代码中的单个函数。但是,如果您知道您的字符串是“App.Model”格式,那么上面的两个衬里就可以了。

      【讨论】:

      • 我认为第二行应该是:your_model = get_model(*your_string.rsplit('.', 1))。应用标签有时是点格式,但型号名称始终是有效标识符。
      • 看起来这在新的apps.get_model 中是没有必要的。 “作为一种快捷方式,此方法还接受 app_label.model_name 形式的单个参数。”
      【解决方案5】:

      在 Django 1.7+ 中这样做的幸运方式是:

      import django
      model_cls = django.apps.apps.get_model('app_name', 'model_name')
      

      因此,在所有框架教程的规范示例中:

      import django
      entry_cls = django.apps.apps.get_model('blog', 'entry')  # Case insensitive
      

      【讨论】:

        【解决方案6】:

        2020 年解决方案:

        from django.apps import apps
        
        apps.get_model('app_name', 'Model')
        

        根据你的例子:

        apps.get_model('people', 'Person')
        

        每: Import Error :cannot import name get_model

        【讨论】:

          【解决方案7】:

          如果您不知道您的模型存在于哪个应用中,您可以这样搜索:

          from django.contrib.contenttypes.models import ContentType 
          ct = ContentType.objects.get(model='your_model_name') 
          model = ct.model_class()
          

          记住 your_model_name 必须是小写的。

          【讨论】:

            【解决方案8】:

            另一种代码更少的版本,适合懒人。在 Django 2+ 中测试

            from django.apps import apps
            model = apps.get_model("appname.ModelName") # e.g "accounts.User"
            

            【讨论】:

              【解决方案9】:

              我不确定它在 Django 中是在哪里完成的,但你可以这样做。

              通过反射将类名映射到字符串。

              classes = [Person,Child,Parent]
              def find_class(name):
               for clls in classes:
                if clls.__class__.__name__ == name:
                 return clls
              

              【讨论】:

              • 是 clls.__class__.__name__ 还是 clls.__name__?
              【解决方案10】:

              这是一种从字符串中获取类的不太特定于 django 的方法:

              mymodels = ['ModelA', 'ModelB']
              model_list = __import__('<appname>.models', fromlist=mymodels)
              model_a = getattr(model_list, 'ModelA')
              

              或者您可以使用 importlib,如图所示 here:

              import importlib
              myapp_models = importlib.import_module('<appname>.models')
              model_a = getattr(myapp_models, 'ModelA')
              

              【讨论】:

                猜你喜欢
                • 2013-12-03
                • 1970-01-01
                • 1970-01-01
                • 2016-03-05
                • 1970-01-01
                • 2012-08-30
                • 1970-01-01
                • 2021-02-26
                • 1970-01-01
                相关资源
                最近更新 更多