【问题标题】:Get model's fields in Django在 Django 中获取模型的字段
【发布时间】:2011-04-08 13:10:13
【问题描述】:

给定一个 Django 模型,我试图列出它的所有字段。我已经看到了一些使用 _meta 模型属性执行此操作的示例,但是 meta 前面的下划线不是表示 _meta 属性是私有属性,不应该直接访问吗? ...因为,例如,_meta 的布局可能会在未来发生变化并且不是一个稳定的 API?

_meta 是这个规则的例外吗?它是否稳定且可以使用,或者访问它是否被认为是不好的做法?或者是否有一个函数或其他方法可以在不使用 _meta 属性的情况下自省模型的字段?下面是一些链接的列表,展示了如何使用 _meta 属性来做到这一点

非常感谢任何建议。

django object get/set field

http://www.djangofoo.com/80/get-list-model-fields

How to introspect django model fields?

【问题讨论】:

标签: django django-models introspection metamodel


【解决方案1】:

fields = [f"{f.name}_id" if f.is_relation else f.name for f in model._meta.fields]

【讨论】:

    【解决方案2】:

    _meta 包含的模型字段作为各个字段对象的列表列在多个位置。将它们作为字典使用可能更容易,其中键是字段名称。

    在我看来,这是收集和组织模型字段对象的最多余和最具表现力的方式:

    def get_model_fields(model):
      fields = {}
      options = model._meta
      for field in sorted(options.concrete_fields + options.many_to_many + options.virtual_fields):
        fields[field.name] = field
      return fields
    

    (参见 django.forms.models.fields_for_model 中的 This example usage。)

    【讨论】:

    • 您可能希望在代码中附上其功能的简要说明。
    【解决方案3】:

    我知道这篇文章已经很老了,但我只是想告诉任何正在搜索相同内容的人,有一个公开的官方 API 可以执行此操作:get_fields()get_field()

    用法:

    fields = model._meta.get_fields()
    my_field = model._meta.get_field('my_field')
    

    https://docs.djangoproject.com/en/3.2/ref/models/meta/#retrieving-all-field-instances-of-a-model

    【讨论】:

    【解决方案4】:

    另一种方法是向模型中添加函数,当您想要覆盖日期时可以调用该函数。

    class MyModel(models.Model):
        name = models.CharField(max_length=256)
        created = models.DateTimeField(auto_now_add=True)
        modified = models.DateTimeField(auto_now=True)
    
        def set_created_date(self, created_date):
            field = self._meta.get_field('created')
            field.auto_now_add = False
            self.created = created_date
    
        def set_modified_date(self, modified_date):
            field = self._meta.get_field('modified')
            field.auto_now = False
            self.modified = modified_date
    
    my_model = MyModel(name='test')
    my_model.set_modified_date(new_date)
    my_model.set_created_date(new_date)
    my_model.save()
    

    【讨论】:

      【解决方案5】:

      根据 django 文档 2.2,您可以使用:

      获取所有字段:Model._meta.get_fields()

      获取单个字段:Model._meta.get_field('field name')

      例如。 Session._meta.get_field('expire_date')

      【讨论】:

        【解决方案6】:

        如果您的 admin 站点需要此功能,还有 ModelAdmin.get_fields 方法 (docs),它返回字段名称为 stringslist

        例如:

        class MyModelAdmin(admin.ModelAdmin):
            # extending change_view, just as an example
            def change_view(self, request, object_id=None, form_url='', extra_context=None):
                # get the model field names
                field_names = self.get_fields(request)
                # use the field names
                ...
        

        【讨论】:

          【解决方案7】:

          get_fields()返回一个tuple,每个元素都是一个Model field类型,不能直接作为字符串使用。因此,field.name 将返回字段名称

          my_model_fields = [field.name for field in MyModel._meta.get_fields()]
          上面的代码将返回一个包含所有字段名称的列表

          示例

          In [11]: from django.contrib.auth.models import User
          
          In [12]: User._meta.get_fields()
          Out[12]: 
          (<ManyToOneRel: admin.logentry>,
           <django.db.models.fields.AutoField: id>,
           <django.db.models.fields.CharField: password>,
           <django.db.models.fields.DateTimeField: last_login>,
           <django.db.models.fields.BooleanField: is_superuser>,
           <django.db.models.fields.CharField: username>,
           <django.db.models.fields.CharField: first_name>,
           <django.db.models.fields.CharField: last_name>,
           <django.db.models.fields.EmailField: email>,
           <django.db.models.fields.BooleanField: is_staff>,
           <django.db.models.fields.BooleanField: is_active>,
           <django.db.models.fields.DateTimeField: date_joined>,
           <django.db.models.fields.related.ManyToManyField: groups>,
           <django.db.models.fields.related.ManyToManyField: user_permissions>)
          
          In [13]: [field.name for field in User._meta.get_fields()]
          Out[13]: 
          ['logentry',
           'id',
           'password',
           'last_login',
           'is_superuser',
           'username',
           'first_name',
           'last_name',
           'email',
           'is_staff',
           'is_active',
           'date_joined',
           'groups',
           'user_permissions']
          

          【讨论】:

            【解决方案8】:

            现在有特殊方法-get_fields()

                >>> from django.contrib.auth.models import User
                >>> User._meta.get_fields()
            

            它接受两个可用于控制返回哪些字段的参数:

            • include_parents

              默认为真。递归地包括在父类上定义的字段。如果设置为 False,get_fields() 将仅搜索直接在当前模型上声明的字段。直接从抽象模型或代理类继承的模型中的字段被认为是本地的,而不是父级的。

            • include_hidden

              默认为假。如果设置为 True,get_fields() 将包含用于支持其他字段功能的字段。这还将包括任何具有以“+”开头的相关名称(例如 ManyToManyField 或 ForeignKey)的字段

            【讨论】:

              【解决方案9】:

              这个怎么样。

              fields = Model._meta.fields
              

              【讨论】:

              • 我想人们可能想要访问一个字段的属性。此外,正如前面的答案所指出的,还有many_to_manyvirtual_fields
              • @Jocke 没错。可能需要访问另一个属性。答案已编辑。
              【解决方案10】:

              _meta 是私有的,但相对稳定。努力将其形式化、记录并删除下划线,这可能发生在 1.3 或 1.4 之前。我想会努力确保事情向后兼容,因为很多人一直在使用它。

              如果您特别关心兼容性,请编写一个接受模型并返回字段的函数。这意味着如果将来发生某些变化,您只需更改一个函数。

              def get_model_fields(model):
                  return model._meta.fields
              

              我相信这将返回Field 对象的列表。要从实例中获取每个字段的值,请使用getattr(instance, field.name)

              更新:Django 贡献者正在开发一个 API 来替换 _Meta 对象,作为 Google Summer of Code 的一部分。请参阅:
              - https://groups.google.com/forum/#!topic/django-developers/hD4roZq0wyk
              - https://code.djangoproject.com/wiki/new_meta_api

              【讨论】:

              • 您还应该知道,如果您还需要多对多字段,您需要访问model._meta.many_to_many
              • 谢谢威尔。很高兴知道其他人也在使用 _meta。我喜欢有一个包装函数的想法。 Lazerscience,也谢谢你。很高兴知道有一个很好的方法来获取 many_to_many 字段。乔
              • django/core/management/commands/loaddata.py 使用 _meta 遍历应用程序、模型和字段树。遵循很好的模式......你可以打赌这是“官方方式”。
              • 如果您使用通用外键,您还应该检查_meta.virtual_fields
              • _meta is now a formal, supported API(Django 1.8 中的新功能)
              【解决方案11】:

              这是 Django 在从模型构建表单时自己完成的事情。它使用 _meta 属性,但正如 Bernhard 所指出的,它同时使用 _meta.fields 和 _meta.many_to_many。查看 django.forms.models.fields_for_model,您可以这样做:

              opts = model._meta
              for f in sorted(opts.fields + opts.many_to_many):
                  print '%s: %s' % (f.name, f)
              

              【讨论】:

                猜你喜欢
                • 2016-03-26
                • 2021-11-27
                • 1970-01-01
                • 1970-01-01
                • 2015-10-12
                • 2016-08-11
                • 2021-07-30
                • 2011-03-07
                • 2020-07-07
                相关资源
                最近更新 更多