Django:获取模型字段列表?

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

我认为我可以通过利用inspect.getmembers(model)来检索这些字段,但它返回的列表不包含这些字段中的任何一个。看起来Django已经掌握了这个类,添加了它所有神奇的属性,并去掉了实际定义的内容。所以…我怎样才能得到这些田地?他们可能有一个功能来检索他们自己的内部目的?

244355 次浏览

Django 1.8及以上版本:

你应该使用get_fields():

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

get_all_field_names()方法是从Django开始弃用 .

. 1.8,并将在1.10中删除

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


1.8之前的Django版本:

model._meta.get_all_field_names()

这样应该可以了。

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

我发现把这个添加到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

这很管用。我只在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来获取它们。

这里提到的get_all_related_fields()方法已经是1.8已弃用。从现在开始,它是get_fields()

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

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

只是补充,我使用self对象,这为我工作:

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

不清楚您拥有的是类的实例还是类本身,并试图检索字段,但无论哪种方式,考虑以下代码

使用实例

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'

至少对于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']
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中为我工作

为什么不直接用它呢:

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

所以在我找到这篇文章之前,我成功地找到了这个方法。

Model._meta.fields

它的工作原理和

Model._meta.get_fields()

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

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

由于大多数答案都过时了,我将尝试更新Django 2.2 这里帖子-你的应用程序(帖子,博客,商店等)

1)从模型出发链接:https://docs.djangoproject.com/en/stable/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 in Organisation._meta.fields]
parent_fields = BlogPost.get_deferred_fields(BlogPost)


list_display = all_fields
read_only = parent_fields

有时候我们也需要db列:

def get_db_field_names(instance):
your_fields = instance._meta.local_fields
db_field_names=[f.name+'_id' if f.related_model is not None else f.name  for f in your_fields]
model_field_names = [f.name for f in your_fields]
return db_field_names,model_field_names

调用该方法获取字段:

db_field_names,model_field_names=get_db_field_names(Mymodel)

结合给定线程的多个答案(谢谢!),并提出以下通用解决方案:

class ReadOnlyBaseModelAdmin(ModelAdmin):
def has_add_permission(self, request):
return request.user.is_superuser


def has_delete_permission(self, request, obj=None):
return request.user.is_superuser


def get_readonly_fields(self, request, obj=None):
return [f.name for f in self.model._meta.get_fields()]

未被别人提及的细节:

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

比如Get

['id', 'name', 'occupation']

而且

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

得到

['id', 'name', 'occupation_id']

如果

reg = MyModel.objects.first()

然后

reg.occupation

比如Get

<Occupation: Dev>

而且

reg.occupation_id

得到

1