与lookups that span relationships类似,我有一个对象,我想动态评估一个指定相关对象属性的字符串。
例如,在question_response
对象上,我想评估survey_response__responder__first_name
。
在列表中,我指定了要在对象上查找并导出到csv的属性。例如['title','question_response_id']。所以基本上我的脚本是获取对象列表,然后获取指定的所有属性并将数据放入csv。 (实际上它是我正在使用的django tablib)。
我希望不仅可以指定该对象的属性,还可以指定关系的属性。我已经有了这个对象,所以我不是从对象管理器开始的。我试图找出是否可以使用跨越关系的属性字符串并对其进行评估。
答案 0 :(得分:2)
据我所知,不是直接的。但是,如果您愿意再次进行数据库搜索,可以轻松完成:
fields = [
'survey_response__responder__first_name',
'survey_response__responder__last_name',
]
known_objects = [obj1, obj2, obj3]
pks = [obj.pk for obj in known_objects]
SomeModel.objects.filter(pk__in = pks).values_list(*fields)
除此之外,对所有这些数据进行一次查询可能是正确的方法; obj1.survey_response.responder.first_name
将执行2个查询:一个用于响应,另一个用于响应者,如果您正在循环obj2
,obj3
等,则会有更多查询,如果您还没有{ {1}}。{/ em>
答案 1 :(得分:1)
django管理员应用程序已经可以执行此操作,因此我在源代码中进行了挖掘,在django.contrib.admin.utils.py
中有许多实用程序函数可以将查找字符串解析为其字段,以便将它们作为过滤器的一部分进行链接一个查询集。特别感兴趣的是get_field_from_path
:
def get_fields_from_path(model, path):
""" Return list of Fields given path relative to model.
e.g. (ModelX, "user__groups__name") -> [
<django.db.models.fields.related.ForeignKey object at 0x...>,
<django.db.models.fields.related.ManyToManyField object at 0x...>,
<django.db.models.fields.CharField object at 0x...>,
]
"""
pieces = path.split(LOOKUP_SEP)
fields = []
for piece in pieces:
if fields:
parent = get_model_from_relation(fields[-1])
else:
parent = model
fields.append(parent._meta.get_field_by_name(piece)[0])
return fields
将此与utils.py
中的其他功能相结合,您就拥有了解决方案。
答案 2 :(得分:1)
仅供参考我发现了另一种类似于@Burhan建议的解决方案,但没有利用utils.py
函数。
在此代码段中找到:http://djangosnippets.org/snippets/2868/
即prep_field
方法:
def prep_field(obj, field):
""" Returns the field as a unicode string. If the field is a callable, it
attempts to call it first, without arguments.
"""
if '__' in field:
bits = field.split('__')
field = bits.pop()
for bit in bits:
obj = getattr(obj, bit, None)
if obj is None:
return ""
attr = getattr(obj, field)
output = attr() if callable(attr) else attr
return unicode(output).encode('utf-8') if output else ""