在Django中获取模型的字段


121

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

_meta是该规则的例外吗?它是否稳定且可以立即使用,还是访问它的不良做法?还是有一种功能或某种其他方法可以在不使用_meta属性的情况下对模型的字段进行内部检查?以下是一些链接的列表,这些链接显示了如何使用_meta属性执行此操作

任何建议深表感谢。

django对象获取/设置字段

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

如何自省Django模型字段?


Answers:


144

_meta是私有的,但相对稳定。我们正在努力对其进行形式化,记录和删除下划线,这可能在1.3或1.4之前发生。我想将会做出努力来确保事物向后兼容,因为无论如何还是有很多人在使用它。

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

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

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

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


45
您还应该知道他的事实,如果您还需要多对多字段,则需要访问model._meta.many_to_many
Bernhard Vallant 2010年

1
谢谢威尔。很高兴知道其他人也在使用_meta。我喜欢具有包装器功能的想法。Lazerscience,也谢谢您。很高兴知道有一个很好的方法来获取many_to_many字段。乔
乔J 2010年

3
django/core/management/commands/loaddata.py使用_meta遍历应用程序,模型和字段的树。可以遵循的好模式...您可以打赌,这是“官方方式”。
滚刀

2
如果您使用通用外键,还应该检查_meta.virtual_fields
andrei1089 2013年

7
_meta现在是正式的,受支持的API(Django 1.8中的新增功能)
mgalgs 2015年

97

我知道这个职位是很老,但我只在乎告诉任何人谁是寻找有一个公众和官方的API做这同样的事情:get_fields()get_field()

用法:

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

https://docs.djangoproject.com/zh-CN/1.8/ref/models/meta/


6
对于较新版本的django,这实际上是正确的答案。
chhantyal 2015年


3
一个问题:如果这些是“公共和官方的”,为什么它们仍在统治之下_meta
krubo

9

现在有一个特殊的方法-get_fields()

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

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

  • include_parents

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

  • include_hidden

    默认为False。如果设置为True,则get_fields()将包含用于支持其他字段功能的字段。这还将包括所有以“ +”开头的具有related_name的字段(例如ManyToManyField或ForeignKey)


9

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

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

示例

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']

好答案!谢谢!
Tms91,19年

8

这是由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)

4

_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中的此示例用法。)


2
您可能需要在代码中附带简短说明。
Bas van Dijk 2013年

2

这个怎么样。

fields = Model._meta.fields

1
我想可能有人想访问一个字段的属性。另外,如先前的答案所指出的,还有many_to_manyvirtual_fields
Jocke

@Jocke对,你是。可能需要访问另一个属性。答案已编辑。
JDE876'9

2

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

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

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

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


1

如果您的管理网站需要此ModelAdmin.get_fields方法,则还有方法(docs),该方法返回list字段名称strings

例如:

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
        ...

0

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

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()
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.