python - 有没有办法用额外的属性来增加 django QuerySets?

标签 python django django-queryset

我正在尝试向 QuerySet 的元素添加一些额外的属性,这样我就可以在模板中使用额外的信息,而不是多次访问数据库。让我举例说明,假设我们有带有作者外键的书籍。

>>> books = Book.objects.filter(author__id=1)
>>> for book in books:
...     book.price = 2  # "price" is not defined in the Book model
>>> # Check I can get back the extra information (this works in templates too):
>>> books[0].price
2
>>> # but it's fragile: if I do the following:
>>> reversed = books.reverse()
>>> reversed[0].price
Traceback (most recent call last):
  ...
AttributeError: 'Book' object has no attribute 'price'
>>> # i.e., the extra field isn't preserved when the QuerySet is reversed.

因此,只要您不使用像 reverse() 这样的东西,就可以向 QuerySet 的元素添加属性。

我目前的解决方法是只使用 select_related() 再次从数据库中获取我需要的额外信息,即使我已经在内存中了。

有更好的方法吗?

最佳答案

这是一个老问题,但我会添加我的解决方案,因为我最近需要它。

理想情况下,我们可以为 QuerySet 使用某种代理对象。然后,我们的代理版本将在迭代期间进行更改。

很难涵盖所有可能的场景,QuerySet 对象有点复杂并且有多种不同的使用方式。但是对于在最后一分钟添加属性因为发送到模板(或通用 View )的简单情况,以下可能有效:

class alter_items(object):

  def __init__(self, queryset, **kwargs):
    self.queryset = queryset
    self.kwargs = kwargs

  # This function is required by generic views, create another proxy
  def _clone(self):
    return alter_items(queryset._clone(), **self.kwargs)

  def __iter__(self):
    for obj in self.queryset:
      for key, val in self.kwargs.items():
        setattr(obj, key, val)
      yield obj

然后像这样使用它:

query = alter_items(Book.objects.all(), price=2)

因为它不是真正的代理,你可能需要根据它的使用方式做进一步的修改,但这是粗略的做法。如果有一种简单的方法可以在 Python 中使用新样式类创建代理类,那就太好了。如果您想使用更完整的实现,外部库 wrapt 可能会有用

关于python - 有没有办法用额外的属性来增加 django QuerySets?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6999989/

相关文章:

python - python 中 numpy 数组的 len()

python - 如何通过 http.client.HTTPSConnection 设置 SNI

Python:为什么我得到 [Errno 13] Permission Denied?

python - 在单个数据库调用中评估多个查询集

django - 如何允许用户查看仅由他添加的数据 Django Admin

django - 如何判断 Django QuerySet 是否已被评估?

Django 在页面之间传递查询集

python - 从数据框中删除包含字符列表之外的字符的行

CreateView 后 django 重定向到以前的 url

django - NOT NULL 约束失败 : history. user_id