Django 从所有查询中排除字段

Pax*_*x0r 2 python django database-migration django-orm django-migrations

我正在 Heroku 上运行 Django,具有零停机功能。这意味着在部署期间,同一数据库上运行两个版本的代码(旧版和新版)。这就是为什么我们需要避免任何向后不兼容的迁移。

是否有可能从给定模型上的 Django 查询中排除字段?

假设我们有一个模型(版本 1):

class Person(models.Model):
    name = models.CharField()
    address = models.TextField()
Run Code Online (Sandbox Code Playgroud)

在未来的某个时间,我们希望将地址移动到单独的表中。我们知道我们不应该删除旧代码要工作的字段,因此 Person 模型可能看起来像(版本 2):

class Person(models.Model):
    name = models.CharField()
    address = models.ForeignKey(Address)
    _address = models.TextField(db_name='address')
Run Code Online (Sandbox Code Playgroud)

这样,如果旧代码查询地址,即使数据库已迁移,它也会从 Person 表中获取地址(这将是旧值,但假设这不是一个大问题)。

现在我如何才能安全地删除_address字段?如果我们部署版本 3 并_address删除字段,则版本 2 的代码仍将尝试_address在 select 上获取,即使它没有在任何地方使用,并且会失败并出现“无此类列”异常。

有没有办法防止这种情况,并在版本 2 的代码中将某些字段标记为“不可获取”?所以版本 2 不会删除字段,但不会再获取它,版本 3 将删除字段。

小智 5

您可以为defer所有查询集的特定字段使用自定义对象管理器。

class CustomManager(models.Manager):
    def get_queryset(self):
        return super(CustomManager, self).get_queryset().defer('_address',)
Run Code Online (Sandbox Code Playgroud)
class Person(models.Model):
    name = models.CharField()
    address = models.ForeignKey(Address)
    _address = models.TextField(db_name='address')

    objects = CustomManager()
Run Code Online (Sandbox Code Playgroud)

之后,默认情况下,在针对Person模型的任何查询集中都不会包含_address查询中的字段。