Django:获取模型字段列表?

mpe*_*pen 172 django django-models

我已经定义了一个User(最终)继承自的类models.Model.我想获得为此模型定义的所有字段的列表.例如,phone_number = CharField(max_length=20).基本上,我想要检索从Field类继承的任何东西.

我以为我可以通过利用来检索这些inspect.getmembers(model),但它返回的列表不包含任何这些字段.看起来Django已经掌握了这个类,并添加了所有的魔法属性,并删除了实际定义的内容.那么......我怎样才能获得这些领域?它们可能具有为自己的内部目的检索它们的功能吗?

ros*_*dia 280

对于Django 1.8及更高版本:

get_fields()方法从Django 1.8开始不推荐使用,将在1.10中删除.

上面链接的文档页面提供了完全向后兼容的实现get_all_field_names(),但是对于大多数用途get_all_field_names()应该可以正常工作.

对于1.8之前的Django版本:

[f.name for f in MyModel._meta.get_fields()]
Run Code Online (Sandbox Code Playgroud)

这应该够了吧.

这需要一个实际的模型实例.如果您拥有的是子类django.db.models.Model,那么您应该调用myproject.myapp.models.MyModel._meta.get_all_field_names()

  • 也想要对象,而不仅仅是他们的名字.这似乎可以在`model._meta.fields`中找到,它们的名字可以用`field.name`检索.我只希望这是检索此信息最稳定的方法:) (11认同)
  • 这是一个很好的解决方案,但是这种方法包括反向关系字段,例如反向ForeignKey,而那些不完全是"字段".有谁知道如何区分实际领域? (3认同)
  • 不完全确定.下划线似乎表明它是一个内部API,如果Django家伙将其提升为对`django.db.models.Model`的实际公共方法调用,那将是很酷的.我会深入研究它,看看我能找到什么 (2认同)
  • 我想通过`_meta`属性来做它是唯一的方法...另外看看ManyMoMany字段的`_meta.many_to_many`! (2认同)
  • @rossipedia:只是注意到 ._meta API 是公开的(虽然它曾经是私有的,可能是在第一次写这个答案时):https://docs.djangoproject.com/en/1.8/ref/models/meta/# django.db.models.options.Options (2认同)

Wil*_*Wil 72

get_all_related_fields()此处提到的方法已在1.8中弃用.从现在开始吧get_fields().

>> from django.contrib.auth.models import User
>> User._meta.get_fields()
Run Code Online (Sandbox Code Playgroud)


bjw*_*bjw 53

我发现将这个添加到django模型非常有帮助:

def __iter__(self):
    for field_name in self._meta.get_all_field_names():
        value = getattr(self, field_name, None)
        yield (field_name, value)
Run Code Online (Sandbox Code Playgroud)

这可以让你做到:

for field, val in object:
    print field, val
Run Code Online (Sandbox Code Playgroud)

  • ForeignKey怎么样?我有这样的错误`django.db.models.fields.related.RelatedObjectDoesNotExist:CustomModel没有custom_attribute. (2认同)
  • `self._meta.get_all_field_names()` 已被折旧并删除。您可以使用“for field in self._meta.get_fields()”之类的内容,然后使用“yield (field.name, field.value_from_object(self))” (2认同)

Mak*_*ks 19

由于大多数答案已过时,因此我将尝试在Django 2.2上更新您的 信息-您的应用(帖子,博客,商店等)

1)从模型链接:https : //docs.djangoproject.com/en/2.2/ref/models/meta/

from posts.model import BlogPost

all_fields = BlogPost._meta.fields
#or
all_fields = BlogPost._meta.get_fields()
Run Code Online (Sandbox Code Playgroud)

注意:

all_fields=BlogPost._meta.get_fields()
Run Code Online (Sandbox Code Playgroud)

也将获得一些关系,例如。您无法在视图中显示。
就我而言:

Organisation._meta.fields
(<django.db.models.fields.AutoField: id>, <django.db.models.fields.DateField: created>...
Run Code Online (Sandbox Code Playgroud)

Organisation._meta.get_fields()
(<ManyToOneRel: crm.activity>, <django.db.models.fields.AutoField: id>, <django.db.models.fields.DateField: created>...
Run Code Online (Sandbox Code Playgroud)

2)从实例

from posts.model import BlogPost

bp = BlogPost()
all_fields = BlogPost._meta.fields
Run Code Online (Sandbox Code Playgroud)

3)从父模型

假设我们将Post作为父模型,并且您希望查看列表中的所有字段,并且在Edit模式下将父字段设为只读。

from django.contrib import admin
from posts.model import BlogPost 




@admin.register(BlogPost)
class BlogPost(admin.ModelAdmin):
    all_fields = [f.name for f Organisation._meta.fields]
    parent_fields = BlogPost.get_deferred_fields(BlogPost)

    list_display = all_fields
    read_only = parent_fields
Run Code Online (Sandbox Code Playgroud)


Ans*_*uez 14

一个别人没有提到的细节:

[f.name for f in MyModel._meta.get_fields()]
Run Code Online (Sandbox Code Playgroud)

得到,例如

['id', 'name', 'occupation']
Run Code Online (Sandbox Code Playgroud)

[f.get_attname() for f in MyModel._meta.get_fields()]
Run Code Online (Sandbox Code Playgroud)

得到

['id', 'name', 'occupation_id']
Run Code Online (Sandbox Code Playgroud)

如果

reg = MyModel.objects.first()
Run Code Online (Sandbox Code Playgroud)

然后

reg.occupation
Run Code Online (Sandbox Code Playgroud)

得到,例如

<Occupation: Dev>
Run Code Online (Sandbox Code Playgroud)

reg.occupation_id
Run Code Online (Sandbox Code Playgroud)

得到

1
Run Code Online (Sandbox Code Playgroud)


Roc*_*ite 12

这样就可以了.我只在Django 1.7中测试它.

your_fields = YourModel._meta.local_fields
your_field_names = [f.name for f in your_fields]
Run Code Online (Sandbox Code Playgroud)

Model._meta.local_fields不包含多对多字段.你应该使用它们Model._meta.local_many_to_many.


Viv*_*and 10

def __iter__(self):
    field_names = [f.name for f in self._meta.fields]
    for field_name in field_names:
        value = getattr(self, field_name, None)
        yield (field_name, value)
Run Code Online (Sandbox Code Playgroud)

这对我有用 django==1.11.8


abo*_*ron 8

MyModel._meta.get_all_field_names()在Django 1.10中被弃用了几个版本并删除了.

以下是来自文档的向后兼容建议:

from itertools import chain

list(set(chain.from_iterable(
    (field.name, field.attname) if hasattr(field, 'attname') else (field.name,)
    for field in MyModel._meta.get_fields()
    # For complete backwards compatibility, you may want to exclude
    # GenericForeignKey from the results.
    if not (field.many_to_one and field.related_model is None)
)))
Run Code Online (Sandbox Code Playgroud)


Nad*_*xan 7

目前尚不清楚您是否具有该类的实例或该类本身,并尝试检索字段,但是无论哪种方式,请考虑以下代码

使用实例

instance = User.objects.get(username="foo")
instance.__dict__ # returns a dictionary with all fields and their values
instance.__dict__.keys() # returns a dictionary with all fields
list(instance.__dict__.keys()) # returns list with all fields
Run Code Online (Sandbox Code Playgroud)

使用课程

User._meta.__dict__.get("fields") # returns the fields

# to get the field names consider looping over the fields and calling __str__()
for field in User._meta.__dict__.get("fields"):
    field.__str__() # e.g. 'auth.User.id'
Run Code Online (Sandbox Code Playgroud)


kee*_*ive 7

至少对于Django 1.9.9——我目前使用的版本——请注意,.get_fields()实际上它也“考虑”了任何外国模型作为一个字段,这可能是有问题的。说你有:

class Parent(models.Model):
    id = UUIDField(primary_key=True)

class Child(models.Model):
    parent = models.ForeignKey(Parent)
Run Code Online (Sandbox Code Playgroud)

它遵循

>>> map(lambda field:field.name, Parent._model._meta.get_fields())
['id', 'child']
Run Code Online (Sandbox Code Playgroud)

同时,如@Rockallite 所示

>>> map(lambda field:field.name, Parent._model._meta.local_fields)
['id']
Run Code Online (Sandbox Code Playgroud)


arr*_*rt_ 6

补充一点,我正在使用自我对象,这对我有用:

[f.name for f in self.model._meta.get_fields()]
Run Code Online (Sandbox Code Playgroud)


Car*_*ker 6

所以在我找到这篇文章之前,我成功地发现它可以工作。

Model._meta.fields
Run Code Online (Sandbox Code Playgroud)

它同样有效

Model._meta.get_fields()
Run Code Online (Sandbox Code Playgroud)

我不确定结果有什么不同,如果有的话。我运行了这个循环并得到了相同的输出。

for field in Model._meta.fields:
    print(field.name)
Run Code Online (Sandbox Code Playgroud)