Django:获取模型字段列表?


196

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

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



Answers:


46

由于大多数答案已过时,因此我将尝试在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()

注意:

all_fields=BlogPost._meta.get_fields()

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

Organisation._meta.fields
(<django.db.models.fields.AutoField: id>, <django.db.models.fields.DateField: created>...

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

2)从实例

from posts.model import BlogPost

bp = BlogPost()
all_fields = bp._meta.fields

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

1
我认为这是正确的,并接受它作为新答案。感谢更新!
mpen19年

@mpen Wont声称这是最好的方法或最pythonic的方法,但是下面将/应该获得您想要在视图中显示的值,因此如果您愿意,则可以使用HTML表的标题。当get_fields()返回一个元组时,您可以对其进行迭代并获取类似于appname的值。下面的Model.field_name清除第二个点的值,包括在字段名中使用下划线的情况以及将其命名为标题,因此请针对每种独特情况根据需要进行修改。 clean_field_names = [str(h).split('.')[2].replace("_", " ").title() for h in all_fields]
亚历杭德罗·苏亚雷斯

1
“来自”实例的示例应为:all_fields = bp._meta.fields
George Kettleborough

@GeorgeKettleborough我明白了。它不是也可以直接在课堂上工作吗?没有可以测试的示例。无论如何,示例都是关于实例的,因此它应该来自bp或至少来自bp。__class__
Maks

294

Django 1.8及更高版本:

您应该使用get_fields()

[f.name for f in MyModel._meta.get_fields()]

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

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


Django 1.8之前的版本:

model._meta.get_all_field_names()

这应该够了吧。

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


11
也想要对象,而不仅仅是它们的名称。model._meta.fields不过似乎可以使用它,并且它们的名称field.name似乎可以检索。我只是希望这是检索此信息的最稳定方法:)
mpen

2
不太确定。下划线似乎表明它是一个内部API,如果Django家伙将其提升为对on的实际公共方法调用,那将很酷django.db.models.Model。我会深入研究,看看能找到什么
rossipedia 2010年

2
我想通过_meta属性来做到这一点是唯一的方法。此外_meta.many_to_many,还要研究ManyToMany字段!
Bernhard Vallant 2010年

3
这是一个很好的解决方案,但是此方法包括反向关系字段(例如反向ForeignKey),而这些字段不完全是“字段”。有人知道如何区分实际字段吗?
viridis

2
@rossipedia:刚才注意到._meta API是公开的(虽然它使用的是私有的,很可能当第一次写这个答案):docs.djangoproject.com/en/1.8/ref/models/meta/...
尼克小号

76

get_all_related_fields()本文中提到的方法已在1.8中弃用。从现在开始get_fields()

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

1
现在,这应该是公认的答案。简洁一点。
Arnaud P

是的,这就是答案。
eric

55

我发现将其添加到Django模型中非常有帮助:

def __iter__(self):
    for field_name in self._meta.get_all_field_names():
        value = getattr(self, field_name, None)
        yield (field_name, value)

这使您可以:

for field, val in object:
    print field, val

2
那ForeignKey呢?我有这样的错误django.db.models.fields.related.RelatedObjectDoesNotExist: CustomModel has no custom_attribute.
SAKrisT 2014年

ForeignKey对我来说很好。虽然,静默捕获所有异常是一种反模式。更好地捕捉AttributeError,或者至少记录一些异常被静默吞下。
Sardathrion-反对SE滥用

1
self._meta.get_all_field_names()已折旧并移除。您可以使用类似的东西for field in self._meta.get_fields(),然后yield (field.name, field.value_from_object(self))
MackM

13

这可以解决问题。我只在Django 1.7中进行测试。

your_fields = YourModel._meta.local_fields
your_field_names = [f.name for f in your_fields]

Model._meta.local_fields不包含多对多字段。您应该使用来获取它们Model._meta.local_many_to_many


10

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

使用实例

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

使用课程

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'

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)

这对我有用 django==1.11.8


8

MyModel._meta.get_all_field_names()弃用的几个版本,背部和去除在Django 1.10。

这是docs中向后兼容的建议:

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

6

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

[f.name for f in self.model._meta.get_fields()]

5

至少在Django 1.9.9(我当前正在使用的版本)中,请注意,.get_fields()实际上也将任何外部模型“考虑”为字段,这可能会出现问题。说您有:

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

class Child(models.Model):
    parent = models.ForeignKey(Parent)

它遵循

>>> map(lambda field:field.name, Parent._model._meta.get_fields())
['id', 'child']

同时,如@Rockallite所示

>>> map(lambda field:field.name, Parent._model._meta.local_fields)
['id']

4

因此,在我找到这篇文章之前,我已经成功地找到了它。

Model._meta.fields

它与

Model._meta.get_fields()

我不确定结果是否有区别。我运行了这个循环,得到了相同的输出。

for field in Model._meta.fields:
    print(field.name)

-2

为什么不使用它:

manage.py inspectdb

输出示例:

class GuardianUserobjectpermission(models.Model):
    id = models.IntegerField(primary_key=True)  # AutoField?
    object_pk = models.CharField(max_length=255)
    content_type = models.ForeignKey(DjangoContentType, models.DO_NOTHING)
    permission = models.ForeignKey(AuthPermission, models.DO_NOTHING)
    user = models.ForeignKey(CustomUsers, models.DO_NOTHING)

    class Meta:
        managed = False
        db_table = 'guardian_userobjectpermission'
        unique_together = (('user', 'permission', 'object_pk'),)

1
这不是问题的答案。
Shayne
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.