重写Django的get_or_create

14 投票
1 回答
7192 浏览
提问于 2025-04-16 12:51

我有一个模型,我重写了它的 save 方法,这样在保存数据之前,可以传入一些数据并自动填充一个字段。下面是我的模型:

class AccountModel(models.Model):

    account = models.ForeignKey(Account)

    def save(self, request=None, *args, **kwargs):
        if request:
            self.account = request.session['account']
        super(AccountModel, self).save(*args, **kwargs)

    class Meta:
        abstract = True

我的想法是,建立一个基础模型,用于那些需要和账户关联的对象,这样每次出现这些对象时,我就不需要每次都处理账户连接(这真的很麻烦)。

但是,我还想使用 get_or_create,这个方法可以在不传入请求的情况下保存新对象。我知道可以不使用 get_or_create,而是用 try/except 来处理,但我想知道有没有办法重写 get_or_create,以及正确的做法是什么

我查看了 Manager 的代码(我想重写的部分),发现 get_or_create 函数只是调用了 QuerySet.get_or_create 函数。也许我可以写一个版本,使用其他管理器的函数,而不是 QuerySet 版本的 get_or_create?你们觉得怎么样?

1 个回答

21

你可以创建一个新的类,继承自 django.db.models.query.QuerySet,然后重写里面的 get_or_create 方法,让它可以接受你的 request 这个参数,并把它传递给 save 方法,不过这样做看起来不是特别优雅。

class AccountQuerySet(models.query.QuerySet):
    def get_or_create(...):
        ...

接着,你可以为你的 Account 模型添加一个自定义的管理器,使用这个自定义的 QuerySet

class AccountManager(models.Manager):
    def get_queryset(self):
        return AccountQuerySet(self.model)

然后在你的模型中使用这个管理器:

class Account(models.Model):
    ...
    objects = AccountManager()

不过你可能会发现,使用 try-except 的方法其实更简洁一些 :)

撰写回答