如何使用 Django 的 ORM 来 TRUNCATE TABLE?

问题描述 投票:0回答:9

要清空数据库表,我使用此 SQL 查询:

TRUNCATE TABLE `books`

如何使用 Django 模型和 ORM 截断表?

我已经尝试过这个,但它不起作用:

Book.objects.truncate()
python sql django orm truncate
9个回答
95
投票

使用 ORM 最接近的是

Book.objects.all().delete()

但也有区别:截断可能会更快,但 ORM 也会追踪外键引用并删除其他表中的对象。


46
投票

您可以通过快速且轻量级的方式来完成此操作,但不能使用 Django 的 ORM。您可以使用 Django 连接游标执行原始 SQL:

from django.db import connection
cursor = connection.cursor()
cursor.execute("TRUNCATE TABLE `books`")

35
投票

可以使用模型的_meta属性填写数据库表名:

from django.db import connection
cursor = connection.cursor()
cursor.execute('TRUNCATE TABLE "{0}"'.format(MyModel._meta.db_table))

重要:这不适用于继承模型,因为它们跨越多个表!

仅适用于 Postgres:对于外键限制,您可以使用

Truncate Cascade
,这也会截断所有相关表。

cursor.execute('TRUNCATE TABLE "{0}" CASCADE'.format(MyModel._meta.db_table))

10
投票

除了 Ned Batchelder 的回答并参考 Bernhard Kircher 的评论:

就我而言,我需要使用网络应用程序清空一个非常大的数据库:

Book.objects.all().delete()

在开发SQLlite环境中,返回:

too many SQL variables

所以我添加了一些解决方法。它可能不是最简洁的,但至少在将截断表选项构建到 Django 的 ORM 中之前它可以工作:

countdata = Book.objects.all().count()
logger.debug("Before deleting: %s data records" % countdata)
while countdata > 0:
    if countdata > 999:
        objects_to_keep = Book.objects.all()[999:]
        Book.objects.all().exclude(pk__in=objects_to_keep).delete()
        countdata = Book.objects.all().count()
    else:
        Book.objects.all().delete()
        countdata = Book.objects.all().count()

顺便说一下,我的一些代码是基于“Django删除查询集最后五个以外的所有内容”。

我在知道答案已经得到解答的情况下添加了此内容,但希望此添加对其他人有所帮助。


9
投票

我知道这是一个非常古老的问题,这里也很少有正确的答案,但我无法抗拒自己分享最优雅和最快的方法来达到这个问题的目的。

class Book(models.Model):
    # Your Model Declaration

    @classmethod
    def truncate(cls):
        with connection.cursor() as cursor:
            cursor.execute('TRUNCATE TABLE {} CASCADE'.format(cls._meta.db_table))

现在要截断 Book 表中的所有数据,只需调用

Book.truncate()

由于这是直接与您的数据库交互,因此它的执行速度会比这样做快得多

Book.objects.all().delete()

2
投票

此代码使用 PosgreSQL 方言。省略级联位以使用标准 SQL。


根据 Shubho Shaha 的回答,您还可以为此创建一个模型管理器。
class TruncateManager(models.Manager):
    def truncate(self, cascade=False):
        appendix = " CASCADE;" if cascade else ";"
        raw_sql = f"TRUNCATE TABLE {self.model._meta.db_table}{appendix}"
        cursor = connection.cursor()
        cursor.execute(raw_sql)

class Truncatable(models.Model):
    class Meta:
        abstract = True

    objects = TruncateManager()

然后,您可以扩展

Truncatable
来创建可截断对象:

class Book(Truncatable):
    ...

这将允许您在从 Truncatable 扩展的所有模型上调用 truncate。

Book.objects.truncate()

我还添加了一个使用级联的标志,该标志(危险区域)还将:“自动截断对任何指定表或由于 CASCADE 添加到组中的任何表具有外键引用的所有表.”,这显然更具破坏性,但将允许代码在原子事务内运行。


0
投票

现在有一个库可以帮助您截断 Django 项目数据库中的特定表,它称为 django-truncate

很简单,只需运行

python manage.py truncate --apps myapp --models Model1
,该表中的所有数据都将被删除!

在这里了解更多信息:https://github.com/KhaledElAnsari/django-truncate


0
投票

对于我来说,要截断我的本地 sqllite 数据库,我最终会得到

python manage.py flush

我最初尝试的是迭代模型并一一删除所有行:

models = [m for c in apps.get_app_configs() for m in c.get_models(include_auto_created=False)]

        for m in models:
            m.objects.all().delete()

但是因为我有受保护的外键,操作的成功取决于模型的顺序。

所以,我正在使用 telush 命令来截断我的本地测试数据库,它对我有用 https://docs.djangoproject.com/en/3.0/ref/django-admin/#django-admin-flush


-1
投票

这并不能直接回答OP的问题,但仍然是一种可以用来实现相同目标的解决方案 - 不同。


好吧,由于一些奇怪的原因(在尝试使用这里其他答案中建议的RAW方法时),我未能截断我的Django数据库缓存表,直到我做了这样的事情:

import commands
cmd = ['psql', DATABASE, 'postgres', '-c', '"TRUNCATE %s;"' % TABLE]
commands.getstatusoutput(' '.join(cmd))

基本上,我不得不通过数据库的实用程序命令发出

truncate
命令 - 在本例中为
psql
,因为我使用的是 Postgres。因此,自动化命令行可能会处理此类极端情况。

可能会节省别人一些时间...

© www.soinside.com 2019 - 2024. All rights reserved.