使用cursor.execute()执行SQL查询时提示“No Such Table”错误,但Customer.objects.raw()可正常运行的原因排查
最近我在Django项目里遇到了一个特别费解的数据库查询问题,折腾半天还是没搞透,来请教下各位:
问题情况
我尝试用两种方式查询customers表,结果一个报错一个完全正常,具体细节如下:
报错的cursor直接查询代码
这段代码每次运行都会抛出Operational Error: No Such Table customers:
cursor = connection.cursor() cursor.execute("SELECT * FROM customers") r = cursor.fetchone() print(r)
正常运行的objects.raw()查询代码
但用Django模型的raw()方法执行完全相同的SQL语句,却能正常获取结果:
sql = "SELECT * FROM customers" customer = Customer.objects.raw(sql)[:10] print(customer) print(connection.queries)
通过debug_toolbar查看执行日志,确认这段代码确实正确命中了目标数据库:
Executed SQL SELECT * FROM customers
Time 1.1129379272460938 ms
Database network_db
额外的奇怪现象
按照Django官方文档的说法,表名应该是应用名_表名的格式,但我尝试把SQL改成SELECT * FROM network_customers时,反而会报错no such table: network_customers,去掉应用名前缀才能正常运行。
我的项目配置信息
数据库配置(settings.py)
DATABASES = { 'default':{ 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', }, 'network_db':{ 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'Network.sqlite3', }, 'simulation_db':{ 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'Simulation.sqlite3', } }
Network应用的apps.py
from django.apps import AppConfig class NetworkConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'network'
我已经通过debug_toolbar确认BASE_DIR路径完全正确,数据库文件位置没有问题,而且用原生sqlite3直接连接文件的方式也能查到数据:
database='C:/EXACTLOCATION/../../Network.sqlite3' db=sqlite3.connect(database) c=db.cursor() sql_command='SELECT * FROM customers' customer = c.execute(sql_command) customer = c.fetchall()
我的核心疑问
- 为什么用
objects.raw()能正常查询,但直接用connection.cursor()就找不到表? - 为什么不需要按照文档要求添加
network_前缀就能查到表?
问题原因解答
1. 数据库连接的指向差异
你直接调用connection.cursor()时,默认使用的是settings里的default数据库(也就是db.sqlite3),但你的customers表实际上是存在network_db对应的Network.sqlite3文件里的!
而Customer.objects.raw()能正常工作,是因为Customer模型属于network应用,Django会自动关联该模型对应的数据库(要么是模型里配置了using参数,要么是项目通过路由/应用配置默认让network应用使用network_db)。
你可以直接验证这个点,修改报错的代码,明确指定使用network_db的连接:
from django.db import connections # 明确指定用network_db的数据库连接 cursor = connections['network_db'].cursor() cursor.execute("SELECT * FROM customers") r = cursor.fetchone() print(r)
这样应该就能正常获取到数据了。
2. 表名前缀消失的原因
通常Django会自动给表名加上应用名前缀,但如果你的Customer模型里显式配置了db_table参数,比如:
class Customer(models.Model): # 你的字段定义 class Meta: db_table = 'customers' # 直接指定表名为customers
那Django就不会自动添加network_前缀了,这就是为什么你用network_customers会找不到表,而直接用customers可以成功查询的原因。你可以去检查下Customer模型的Meta类是不是有这个配置。
内容的提问来源于stack exchange,提问作者RedRum

