我已经创建了一个自定义Manager
,但在我的情况下,它的方法在模型中的特定字段的末尾添加了一些字符串,而不是像通常情况那样只过滤查询集。
我的目标是在调用SomeModel.objects
时返回已经更改的对象。 Django的文档说:
您可以通过覆盖Manager.get_queryset()方法来覆盖Manager的基本QuerySet。 get_queryset()应返回具有所需属性的QuerySet。
当我调用SomeModel.objects.all()
时,我的方法有效,但如果我为objects
应用了一些过滤器,或者在.all()
之后,我可以看到数据变得正常。
models.朋友:
class BaseModelQuerySet(models.QuerySet):
def edit_desc(self, string):
if self.exists():
for obj in self:
if 'description' in obj.__dict__:
obj.__dict__['description'] += string
return self
class BaseModelManager(models.Manager):
def get_queryset(self):
return BaseModelQuerySet(self.model, using=self._db).edit_desc('...extra text')
class BaseModel(models.Model):
objects = BaseModelManager()
class Meta:
abstract = True
壳牌产量:
>>> Macro.objects.all()[0].description
'Test text...extra text'
>>> Macro.objects.all().filter(id=1)[0].description
'Test text'
这让我感到困惑。这种印象是其他方法调用常规查询集而不是使用自定义objects
返回的方法。
返回查询集的Queryset方法实际上返回一个新的查询集(它们不会更改当前的查询集)。并不是他们返回“常规”查询集,它们是自定义查询集子类的实例(您可以通过检查查询集类型自行检查),但尚未调用edit_desc()
方法。
从技术上讲,你可以通过覆盖所有的exclude / filter / ect方法来“解决”这个问题来重新应用你的edit_desc()
方法,但它会非常低效(甚至比它实际上更多),所以你可能想重新考虑你真正的问题是什么以及如何以更有效和更少侵入性的方式解决它。也许解释一下你的具体用例可以为如何解决它提供更好的答案?
编辑:给出您的评论,一个可能的(并且更有效)解决方案是覆盖产生或返回模型实例(或仅仅是原始值)的QuerySet
部分,以便您可以在此处理模型实例/数据。你可能想看看django / db / query.py,特别是ModelIterable
和ValueIterable
类。这比你目前的解决方案要多得多,但是......
另一个可能更简单的解决方案,如果你只关心模型实例(不是原始数据)可能是使用ModelProxy
,覆盖它的__init__
方法来添加你的处理...
最后我意识到,queryset方法实际上并不适用于queryset对象。相反,他们添加了一些额外的SQL语法并再次对数据库执行查询。
因此,更改对象的数据而不保存它,然后尝试执行某些过滤等将导致再次查询DB并检索初始数据。
如果有人在我的问题中有类似的用例,那么不幸的是另一种方法需要。可能的是:
无论如何,非常感谢@bruno desthuilliers和他的建议,如果有人有更好的想法,很乐意在评论中看到它们。