Django:禁用delete()方法的二进制日志

2024-10-01 09:27:56 发布

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

我有一个MySQL主从配置,我只想删除一些主服务器上的旧记录并保留在从服务器上:

class MonitorQuerySet(models.QuerySet):
    def delete(self, *args, **kwargs):
        with connection.cursor() as cur:
            cur.execute('SET @@session.sql_log_bin = 0')
            ret = super().delete(*args, **kwargs)
            cur.execute('SET @@session.sql_log_bin = 1')
        return ret

class Monitor(models.Model):
...
    objects = models.Manager()
    nobinlog = MonitorQuerySet.as_manager()

这种方法的问题是,现在可以执行Monitor.nobinlog.delete(),这将消除整个表。你知道吗

我认为大约有pre_deletepost_delete信号,但这将在每次调用delete()时运行。你知道吗

有没有更好的解决办法?你知道吗


Tags: 服务器logexecutesqlbinmodelssessionas
1条回答
网友
1楼 · 发布于 2024-10-01 09:27:56

我想你指的是这样一个事实:你通常必须明确地说出Monitor.objects.all().delete()。您可以通过分别实现manager和queryset来获得该行为,而不是使用as_manager从queryset创建manager,如下所示:

class NoBinLogQuerySet(models.QuerySet):
    def delete(self, *args, **kwargs):
        with connection.cursor() as cur:
            cur.execute('SET @@session.sql_log_bin = 0')
            ret = super().delete(*args, **kwargs)
            cur.execute('SET @@session.sql_log_bin = 1')
        return ret

class NoBinLogManager(models.Manager):
    def get_queryset(self):
        return NoBinLogQuerySet(self.model, using=self._db)

class Monitor(models.Model):
    ...
    objects = models.Manager()
    nobinlog = NoBinLogManager()

这并不能保护您避免将.filter()的参数弄错并意外删除数据。你知道吗

如果您有一组固定的条件,比如“超过30天的记录”,我会编写一个实用方法,而不是创建一个额外的管理器。在这个方法中,您可以硬编码条件。作为额外的安全措施,您可以添加dry_run参数,该参数将返回将被删除的记录。像这样:

def delete_old_records(dry_run=True):
    kwargs = {'updated_at__lt': now() - timedelta(days=30)}
    if dry_run:
        ret = Monitor.objects.filter(**kwargs)
    else:
        with connection.cursor() as cur:
            cur.execute('SET @@session.sql_log_bin = 0')
            ret = Monitor.objects.delete(**kwargs)
            cur.execute('SET @@session.sql_log_bin = 1')
    return ret

根据执行此方法的方式,请考虑创建自定义管理命令。你知道吗

相关问题 更多 >