You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

重写Django models.Manager的get_queryset方法时触发表不存在错误

解决Django makemigrations时自定义管理器触发的ProgrammingError

问题场景

你在Django中创建了存储音乐的Music模型,通过自定义管理器CustomManager在获取查询集时自动更新所有对象的last_queried_at字段,但执行makemigrations命令时出现以下错误:

django.db.utils.ProgrammingError: relation "app_music" does not exist
LINE 1: UPDATE "app_music" SET "last_queried_at" = '2...

问题原因

  1. 迁移阶段表未创建:你的CustomManager设置了use_in_migrations = True,导致Django在迁移过程中使用该管理器。但此时app_music表还未被创建,执行queryset.update()必然触发表不存在的错误。
  2. 逻辑不合理:在get_queryset()中对全表执行update操作,每次获取查询集都会修改所有数据,既不符合业务逻辑,也会引发性能问题。

解决方案

1. 移除迁移中使用自定义管理器的配置

修改CustomManager,删除use_in_migrations = True这一行,让迁移过程使用默认管理器:

class CustomManager(models.Manager):
    # 移除该行,避免迁移时调用自定义管理器
    # use_in_migrations = True

    def get_queryset(self):
        return super().get_queryset()

2. 正确实现last_queried_at的更新逻辑

不要在获取整个查询集时全表更新,而是针对单个查询对象进行更新,推荐两种实现方式:

方式一:重写get()方法

当通过get()获取单个对象时自动更新字段:

from django.utils import timezone

class CustomManager(models.Manager):
    def get(self, *args, **kwargs):
        obj = super().get(*args, **kwargs)
        obj.last_queried_at = timezone.now()
        # 仅更新指定字段提升性能
        obj.save(update_fields=['last_queried_at'])
        return obj

方式二:添加自定义查询方法

创建专门的方法用于获取并更新对象,业务代码中按需调用:

from django.utils import timezone

class CustomManager(models.Manager):
    def fetch_and_update(self, *args, **kwargs):
        obj = self.get(*args, **kwargs)
        obj.last_queried_at = timezone.now()
        obj.save(update_fields=['last_queried_at'])
        return obj

使用示例:music_obj = Music.objects.fetch_and_update(id=1)

额外优化建议

如果你的需求是定期清理超过一个月未查询的音乐文件,建议使用Django的任务调度工具(如django-celery-beat)编写定时任务,定期执行清理逻辑,而非在查询管理器中做全表更新操作。

内容的提问来源于stack exchange,提问作者Mohirbek Mustaqimov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 09:15:59