1

与跨越关系的查找类似,我有一个对象,我想动态评估一个指定相关对象属性的字符串。

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

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

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

4

3 回答 3

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如果您还没有select_related()使用它们。

于 2013-07-29T19:24:41.893 回答
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,您就有了解决方案。

于 2013-07-29T20:06:30.277 回答
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 ""
于 2013-07-29T20:29:52.513 回答