【问题标题】:How can I introspect properties and model fields in Django?如何自省 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 来获取模型字段,但这并没有给我属性而不是真正的数据库字段。

【问题讨论】:

    标签: python django models


    【解决方案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 的解决方案。
      猜你喜欢
      • 2022-01-24
      • 2019-09-06
      • 2014-11-23
      • 1970-01-01
      • 2016-01-27
      • 2014-06-10
      • 2012-06-09
      • 2011-06-06
      • 2012-11-18
      相关资源
      最近更新 更多