Django中related模型的getattr()

0 投票
1 回答
2772 浏览
提问于 2025-04-21 07:37

我在我的Django项目中有一个叫做people的类:

class People(models.Model):
   user        = models.OneToOneField(User, unique=True)
   adress      = models.CharField(max_length=500)

   def __unicode__(self):
    return "%s %s" % (self.user.first_name, self.user.last_name) 
   def get_all_fields(self):
    return self._meta.fields + self.user._meta.fields

我创建了一个视图,用来把Django数据库中的模型导出到一个CSV文件里。当然,如果能把相关模型的信息,比如Django用户的信息,也一起导出就更好了。

但是当我用下面的代码遍历我的people列表时:

people = People.objects.all()

for p in people:
row = ""
for field in p.get_all_fields():
     row     += str(getattr(p, field.name)) + ','

我遇到了一个错误:'People'对象没有'password'这个属性。显然,它是没有这个属性的,但我该如何使用与'People'相关的外部对象,通过getattr()来获取呢?

编辑

最后,我通过在我的类中使用一些额外的函数,写了一个小的解决方法。

class People(models.Model):
   user        = models.OneToOneField(User, unique=True)
   adress      = models.CharField(max_length=500)

   def __unicode__(self):
      return "%s %s" % (self.user.first_name, self.user.last_name) 

   def get_all_fields(self):
      return self._meta.fields + self.user._meta.fields

   def get_attribute(self, field_name):
      name_list = self.get_field_names()
      if field_name in name_list:
        return unicode(getattr(self, field_name))
      else:
        return unicode(getattr(self.user, field_name))

   def get_field_names(self):
      name_list   = []
      for field in self._meta.fields:
        name_list.append(field.name)
      return name_list

1 个回答

0

也许你可以把这个混合类加到你的People类里面:

class GetNestedFieldsMixin(object):
    link_fields = set((u"ForeignKey", u"OneToOneField"))

    @classmethod
    def _get_nested_fields(cls, obj):
        for field in obj._meta.fields:
            value = field.value_from_object(obj)
            is_link = field.get_internal_type() in cls.link_fields
            if is_link:
                nested_obj = field.rel.to.objects.get(pk=value)
                for name, field, value in  cls._get_nested_fields(nested_obj):
                    yield name, field, value
            else:
                yield obj._meta.object_name, field.name, \
                    field.value_to_string(obj)

    def get_nested_fields(self):
        return self._get_nested_fields(self)

class People(GetNestedFieldsMixin, models.Model):
    ...

for p in people:
    for model_name, field, value in p.get_nested_fields():
        print(model_name, field, value)

如果人数变多了,你应该使用.select_related来避免在内部循环中进行数据库查询。而link_fields可能不太对。这个只是给你一个参考的想法 :).

撰写回答