如何自省 Django 中的属性和模型字段?

Posted

技术标签:

【中文标题】如何自省 Django 中的属性和模型字段?【英文标题】:How can I introspect properties and model fields in Django? 【发布时间】:2011-06-23 06:11:59 【问题描述】:

我正在尝试获取给定对象的所有现有模型字段和属性的列表。有没有一种干净的方法来内省对象,以便我可以获得字段和属性的字典。

class MyModel(Model)
    url = models.TextField()

    def _get_location(self):
        return "%s/jobs/%d"%(url, self.id)

    location = property(_get_location)

我想要的是返回一个看起来像这样的字典:


  'id' : 1,
  'url':'http://foo',
  'location' : 'http://foo/jobs/1'
   

我可以使用model._meta.fields 来获取模型字段,但这并没有给我属性而不是真正的数据库字段。

【问题讨论】:

【参考方案1】:

如果您只需要模型字段和属性(使用属性声明的),那么:

def get_fields_and_properties(model, instance):
    field_names = [f.name for f in model._meta.fields]
    property_names = [name for name in dir(model) if isinstance(getattr(model, name), property)]
    return dict((name, getattr(instance, name)) for name in field_names + property_names)

instance = MyModel()
print get_fields_and_properties(MyModel, instance)

这里唯一额外的一点是通过 class 来查找对应于属性描述符的字段。通过类访问它们会得到描述符,而通过实例会得到值。

【讨论】:

谢谢 - 这正是我所需要的。我试图在实例中寻找“属性”类型的东西,但我应该在类中寻找它们。【参考方案2】:

问题是你说你只想要字段,然后通过将属性混入其中使事情变得复杂。在 Python 中没有任何简单的方法可以区分属性和任何其他随机方法。这与 Django 没有任何关系:只是属性只是一个通过描述符访问的方法。因为类中的任意数量的事物也都是描述符,所以您很难区分它们。

有什么理由不能在类级别定义一个包含所有你想要的属性的列表,然后只对每个元素调用getattr

【讨论】:

【参考方案3】:

您应该在您的实例上使用 dir() 函数。跳过以 '__' 开头的任何内容,然后使用 getattr 从您的实例中获取值。

properties = [prop for prop in dir(SomeClass) if not prop.startswith("__")]

obj = 
for prop in properties:
    obj[prop] = getattr(myinstance, prop)

【讨论】:

不适用于 Django 模型。对象还有很多其他可用的方法和变量(继承自基础 Django Model 类),但严格来说不是 Django 字段或属性。我需要能够区分属性/字段和其他东西。 澄清一下——我指的是内置的“属性”(adam.gomaa.us/blog/2008/aug/11/the-python-property-builtin)——不仅仅是python对象的通用属性。 @shreddd:比较你所拥有的与 model._meta.fields 以区分数据库字段和属性。 对不起 - 我想你误解了这个问题。请参阅我正在寻找的答案的公认解决方案。事实证明,不知道实例中是否有“属性”类型的东西——你需要检查类。【参考方案4】:
class Awesome(models.Model):
 foo = models.TextField()
 bar = models.CharField(max_length = 200)

awe = Awesome()
for property in awe.__dict__.copy():
 # pass private properties.
 if not property.startswith('_'):
  print property,getattr(awe,property)

这就是他们在 Django 中的做法。

【讨论】:

这让我得到了字典中的所有东西,但不是使用 property() 声明的东西。看起来我需要直接从 Model 类中提取它。请参阅上面 John Montgomery 的解决方案。

以上是关于如何自省 Django 中的属性和模型字段?的主要内容,如果未能解决你的问题,请参考以下文章

Python 自省:如何获取对象属性的“未排序”列表?

计算机程序中的自省程序(反射程序)(introspective program)是什么?(introspectableintrospection)

函数自省

Python自省与反射

python学习之自省/反射

如何在 Python 2.x 中对对象执行自省?