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

8 投票
4 回答
12557 浏览
提问于 2025-04-16 11:26

我想获取一个对象中所有现有的模型字段和属性的列表。有没有简单的方法可以检查一个对象,以便我能得到一个字段和属性的字典。

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 来获取模型字段,但这并不能给我那些是属性但不是实际数据库字段的内容。

4 个回答

0
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中是怎么做的。

1

问题在于,你说你只想要字段,但又把属性扔进来了,这就让事情变得复杂了。在Python中,其实没有简单的方法来区分一个属性和其他普通的方法。这跟Django没有关系:属性其实就是通过描述符访问的方法。因为类里面的很多东西也会是描述符,所以你会很难区分它们。

有没有什么理由让你不能在类里面定义一个列表,把你想要的所有属性都放进去,然后对每个元素调用 getattr 呢?

18

如果你只想要模型中的字段和属性(那些用属性声明的),那么可以这样做:

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,找出和属性描述符对应的字段。通过类来访问这些字段会得到描述符,而通过实例访问则会得到实际的值。

撰写回答