更改数据的Django自定义管理器方法与其他管理器方法(filter、get等)一起工作不正确

2024-04-24 15:27:39 发布

您现在位置:Python中文网/ 问答频道 /正文

我已经创建了一个自定义的Manager,但是在我的例子中,它的方法在模型中的特定字段的末尾添加了一些字符串,而不是像通常情况下那样过滤queryset。在

我的目标是在调用SomeModel.objects时返回已更改的对象。Django的文件说:

You can override a Manager’s base QuerySet by overriding the Manager.get_queryset() method. get_queryset() should return a QuerySet with the properties you require.

我的方法是有效的,当我调用SomeModel.objects.all()时,但是如果我为objects或者在.all()之后应用一些过滤器,我可以看到数据变得非常规则。在

模型.py:

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

外壳输出:

^{pr2}$

这让我很困惑。这样的印象是,其他方法调用正则queryset而不是使用custom objects返回。在


Tags: the方法模型selfobjgetreturnobjects
2条回答

最后,我意识到queryset方法实际上并不适用于queryset对象。相反,它们会添加一些额外的SQL语法,并再次对数据库执行查询。在

因此,在不保存对象数据的情况下更改对象的数据,然后尝试执行某些筛选等操作,将导致再次查询数据库并检索初始数据。在

如果有人有与我问题中类似的用例,不幸的是,需要另一种方法。可能包括:

  • 重新定义queryset方法,使它们在本地queryset上工作,就像list一样(不是首选方法,可能会导致默认django行为中的各种问题)
  • 创建与主模型逻辑相关的额外模型(可能会很好)

无论如何,非常感谢@bruno deshuilliers和他的建议,如果有人有更好的想法,会很高兴看到他们的评论。在

返回Queryset的Queryset方法实际上返回一个newQueryset(它们不会就地更改当前的Queryset)。并不是说它们返回的是“regular”queryset,它们是自定义queryset子类的实例(您可以通过检查queryset类型来自己检查),但是尚未对它们调用edit_desc()方法。在

从技术上讲,您可以通过重写所有exclude/filter/ect方法来重新应用您的edit_desc()方法来“解决”这个问题,但是它的效率非常低(甚至比实际的效率更高),所以您可能需要重新考虑一下您的真正的问题是什么,以及如何以更有效、更不具侵入性的方式解决它。也许解释一下你的具体用例可以在如何解决它上找到更好的答案 ? 在

EDIT:根据您的注释,一个可能的(而且更有效的)解决方案是重写产生或返回模型实例(或仅原始值)的QuerySet部分,这样您就可以在此时处理模型实例/数据。您可能想看看django/db/查询.py,特别是ModelIterable和{}类。这比你目前的解决方案要多做很多工作,但是。。。在

如果您只关心模型实例(而不是原始数据),另一个可能更简单的解决方案是使用ModelProxy,重写它的__init__方法来添加此时的处理。。。在

相关问题 更多 >