django评估跨越对象关系的字符串

时间:2013-07-29 19:21:03

标签: django

lookups that span relationships类似,我有一个对象,我想动态评估一个指定相关对象属性的字符串。

例如,在question_response对象上,我想评估survey_response__responder__first_name

在列表中,我指定了要在对象上查找并导出到csv的属性。例如['title','question_response_id']。所以基本上我的脚本是获取对象列表,然后获取指定的所有属性并将数据放入csv。 (实际上它是我正在使用的django tablib)。

我希望不仅可以指定该对象的属性,还可以指定关系的属性。我已经有了这个对象,所以我不是从对象管理器开始的。我试图找出是否可以使用跨越关系的属性字符串并对其进行评估。

3 个答案:

答案 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个查询:一个用于响应,另一个用于响应者,如果您正在循环obj2obj3等,则会有更多查询,如果您还没有{ {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 ""