我正在尝试向 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/