如何根据上下文将属性添加到QuerySet的模型

时间:2013-10-24 20:19:29

标签: django django-models

在没有污染模型的情况下,你们如何根据一些商业规则在你的模型中添加额外字段而不会污染模型?

假设我有一个QuerySet包含Member类型的模型。

检索这些模型后,我想动态添加一个属性online(不在数据库中)。

我希望能够根据从缓存服务器检索的值设置此属性,如:

members_online = get_online_members_ids()
for m in members.all():
    m.online = m.id in members_online

此代码段不起作用,因为1).all()会返回QuerySet的副本,2)我的模型中不存在属性online

之后在我的模板中,我希望能够打印online属性。

我在Django的第一步,请详细说明我的问题,谢谢!

修改

我的问题有点复杂......我的成员列表实际上是另一个模型的关系:

categories = Category.objects.select_related('members').all()
for cat in categories:
    for m in cat.members.all()
        m.online = m.id in members_online

类别是发送给我的模板/活塞处理程序的内容。

2 个答案:

答案 0 :(得分:1)

原因2无关紧要:与所有Python对象一样,Django模型可以随时应用任何属性。

要解决原因1,您只需转换为列表:

all_members = members.objects.all()
for m in all_members:
    m.online = m.id in members_online

现在将all_members传递给模板。

另一种方法是将members_online单独传递给模板,并在那里单独检查状态:

{% for m in members %}
    {% if m.id in members_online %}online{% endif %}
{% endfor %}

如果您需要多次使用每个成员的在线状态(尽管如此,您可以使用with将当前状态保存到临时变量),效率会降低。

答案 1 :(得分:1)

我之前从未使用过这种方法,但现在想一想,我想出了类似的东西:

class Member(models.Model):
    # your fields

    @property
    def online(self):
        # load the list if it wasn't loaded before and save it as a class attribute.
        # that way `get_online_members_ids()` will be called the first time this
        # property is accessed, and that one time only.
        if not hasattr(Member, 'members_online'):
            Member.members_online = get_online_members_ids()
        return self.pk in Member.members_online  # return online status for the particular member

然后,您可以在模板中使用它,就像普通字段一样:

{% for member in members %}
    {{ member.online }}
{% endfor %}

更新:更多地考虑这个问题我认为你需要小心,因为有可能一旦加载静态属性会比你期望的更长久,并在后续请求中重用。我自己没有测试过。