django.db.utils.OperationalError:(1052,“字段列表中的列'名称'不明确”)
Posted
技术标签:
【中文标题】django.db.utils.OperationalError:(1052,“字段列表中的列\'名称\'不明确”)【英文标题】:django.db.utils.OperationalError: (1052, "Column 'name' in field list is ambiguous")django.db.utils.OperationalError:(1052,“字段列表中的列'名称'不明确”) 【发布时间】:2018-11-10 02:38:59 【问题描述】:在我的 Django 项目中,当我查询数据时出现以下错误:
django.db.utils.OperationalError: (1052, "字段列表中的列 'name' 不明确")
使用:
http://localhost:8000/api/physicalserver/list/?switchesport__bandwidth=10
但如果我使用:
http://localhost:8000/api/physicalserver/list/?switches__id=xxx
它会正常工作的。
我的 ListAPIView 代码:
class PhysicalServerListAPIView(ListAPIView):
serializer_class = PhysicalServerListSerializer
permission_classes = [AllowAny]
pagination_class = CommonPagination
def get_queryset(self):
query_params = self.request.query_params
filters = '__contains'.format(key): value
for key, value in query_params.items()
qs = PhysicalServer.objects.filter(**filters)
return qs.extra(select='length':'Length(name)').order_by('length', 'name')
我的序列化代码:
class PhysicalServerListSerializer(ModelSerializer):
bandwidth = serializers.SerializerMethodField()
class Meta:
model = PhysicalServer
fields = "__all__"
depth = 1
def get_bandwidth(self, obj):
return obj.switchesport.bandwidth
我的 PhysicalServer 模型:
class PhysicalServer(models.Model):
name = models.CharField(max_length=32)
switches = models.ForeignKey(to=Switches, on_delete=models.DO_NOTHING)
physical_server_model = models.ForeignKey(to=PhysicalServerModel, null=True, on_delete=models.DO_NOTHING)
switchesport = models.OneToOneField(to=SwitchesPort, related_name="physical_server", on_delete=models.DO_NOTHING)
...
EDIT-1
我的开关型号:
class Switches(models.Model):
name = models.CharField(max_length=32)
desc = models.CharField(max_length=256)
routerdevice = models.ForeignKey(to=RouterDevice, related_name="switches")
gatewaydevice = models.ForeignKey(to=GatewayDevice, related_name="switches")
ctime = models.DateTimeField(auto_now_add=True)
uptime = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-name']
def __str__(self):
return self.name
def __unicode__(self):
return self.name
还有我的 SwitchesPort 型号代码:
class SwitchesPort(models.Model):
name = models.CharField(max_length=32, unique=True)
desc = models.CharField(max_length=256, null=True, blank=True)
switches = models.ForeignKey(to=Switches, on_delete=models.CASCADE,related_name="switchesports")
vlanedipv4networkgroup = models.ForeignKey(
to=VlanedIPv4NetworkGroup,
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="switchesports")
bandwidth = models.IntegerField(default=10)
ctime = models.DateTimeField(auto_now_add=True)
uptime = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['name']
def __str__(self):
return self.name
def __unicode__(self):
return self.name
Edit-2
我的PhysicalServerModel
,(应该是PhysicalServerType
):
class PhysicalServerModel(models.Model):
name = models.CharField(max_length=32)
desc = models.CharField(max_length=256)
cpu = models.CharField(null=True, blank=True, max_length=64)
ram = models.CharField(null=True, blank=True, max_length=64)
disk = models.CharField(null=True, blank=True, max_length=64)
bandwidth = models.CharField(null=True, blank=True, max_length=64, default=10)
price = models.DecimalField(null=True, blank=True, max_digits=8, decimal_places=2, max_length=16)
ctime = models.DateTimeField(auto_now_add=True)
uptime = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-id']
def __str__(self):
return self.name
def __unicode__(self):
return self.name
我的 djangorestframework 版本是3.7.1
,django 版本是1.11.1
。我使用mysql
作为我的数据库。
EDIT-3
到目前为止,我们发现问题是因为当我尝试在PhysicalServerListAPIView
中按length
排序时,name
字段不明确:
return qs.extra(select='length':'Length(name)').order_by('length', 'name')
如果我直接返回qs
,我就不会有这个问题了。
【问题讨论】:
在 SQL 连接期间似乎有些模棱两可。请添加您的Switches
型号?
@JerinPeterGeorge 查看我的编辑。
从两个模型中删除 Meta
ordering
是否可以解决问题?
@richard_ 为什么你认为是订购造成的?反正我评论了Meta,没有迁移,测试了一下,不行。
您发布的代码难以复制。请注意,包含您的导入语句是 MCVE 的一部分(特别是完整且可验证)。请参阅meta.***.com/questions/312045/… 进行讨论。
【参考方案1】:
问题在于您的 get_queryset 代码。
你有
return qs.extra(select='length':'Length(name)').order_by('length', 'name')
更新:@Simon Charette 指出这里不需要.extra()
,因为这种行为可以在不依赖它的情况下完成。
正如 Simon 所建议的那样,您最好的选择是尽可能多地使用 Django 的 ORM,并且只有在其他方法都失败时才使用 .extra()
。他建议做.order_by(Length('name'), name)
可能是您想要实现的最佳解决方案。
再多研究一下,现在应该使用.extra()
、.annotate()
或仅使用 ORM 的基本功能,如.order_by()
。这是 Reddit 上的short discussion,很容易理解。
-
如果您可以仅使用 ORM 的函数完成您想要完成的工作,那就去做吧!
如果需要,请返回
.annotate()
为查询添加额外信息
如果您需要做的事情不能使用上述工具,请使用.extra()
如果失败,请使用.raw()
使用手动 SQL 查询
当然,一切都可以使用手动 SQL 查询来完成,但抽象层的全部意义在于尽可能多地使用它。
如果你想通电并使用额外的电源,你必须这样做:
return qs.extra(select='length':'Length(APP_NAME_MODEL_NAME.name)').order_by('length', 'api_MODELNAME.name')
当然,将 APP_NAME 和 MODEL_Name 替换为您的值。对我来说,它是 api_switchesport。请参阅下面关于检查 Django 如何在“通过直接连接到您的数据库进行调试”部分中实际命名您的表的建议。
同样,按照 Simon 的建议,我认为您甚至不需要在您的视图中使用 get_queryset 函数,只需在您的 urls.py 中执行以下操作:
from django.db.models.functions import Length
urlpatterns = [
url(r'^physicalserver/list/$',
PhysicalServerListAPIView.as_view (queryset=
PhysicalServer.objects.all().order_by(
Length('name'), 'name'
)
), name='physicalserver-list'),
]
调试 SQL
这里的主要问题是/曾经是 SQL 查询不起作用。也许对你来说,也对那些可能发现这一点的人来说,让我回顾一下在 Django 中调试 SQL。
记录所有查询
查看有关记录所有查询的这个问题(以及查看发生的查询的interesting tool)
显示一个查询
要仅显示一个问题查询,您可以执行以下操作(我包含了您的示例,但将 qs.extra 替换为您可能需要调试的另一个查询):
更多详情请看这里:django orm, how to view (or log) the executed query?
from django.db import connection
result = qs.extra(select='length':'Length(_.name)'.format(appname, field)).order_by('length', '_.name'.format(appname, field))
print(connection.queries)
return result
在 Shell 中调试
我在这里并没有太多使用这种方法,但这是你开始的方式
-
键入
python manage.py shell
启动一个shell
from django.db import connection
测试 ORM python 命令。见playing with the api
通过直接连接到您的数据库进行调试
这个是这里最有趣的,因为 Django 为我们做了很多决定,我们可能不知道数据库中的列名等基础知识。
要连接到 MySQL 数据库(SQLite 是默认数据库,但 qg_java_17137 使用 MySQL)我输入了sudo mysql
,但其他各种问题回答了如何连接到不同类型的数据库。对于 SQLite,这将是 sqlite3 example.db
或类似的命令。
这给了我一个提示 mysql>
输入命令。
-
列出您的数据库:
SHOW DATABASES;
连接到您的数据库:USE your_database_name_here;
显示您的表格:SHOW TABLES;
这让我得到了这个列表:
+----------------------------+
| Tables_in_sandbox |
+----------------------------+
| api_gatewaydevice |
| api_physicalserver |
| api_physicalservermodel |
| api_routerdevice |
| api_switches |
| api_switchesport |
| api_vlanedipv4networkgroup |
| auth_group |
| auth_group_permissions |
| auth_permission |
| auth_user |
| auth_user_groups |
| auth_user_user_permissions |
| django_admin_log |
| django_content_type |
| django_migrations |
| django_session |
+----------------------------+
这告诉我们一件有趣的事情。 Django 已将我的应用程序名称(“api”)添加到数据库中的所有表中。这是有道理的,因为不同的应用程序通常有同名的表,但是因为 Django 为我们做出了这个决定,我们可能不知道我们表的实际名称!
测试您从“调试一个查询”步骤获得的查询。
SELECT (Length(api_switchesport.name)) AS length
, api_physicalserver
.id
, api_physicalserver
.name
, api_physicalserver
.switches_id
, api_physicalserver
.physical_server_model_id
, @ 987654358@.switchesport_id
发件人api_physicalserver
内连接api_switchesport
ON
(api_physicalserver
.switchesport_id
= api_switchesport
.id
)
WHERE api_switchesport
.bandwidth
LIKE '%10%' ORDER BY length
ASC;
对我来说,此查询成功执行,但如果它为您抛出错误,请尝试修改内容。特别是字段名称api_switchesport.name
。最初对我来说就像 name
一样出现,并且由于几乎所有表都有名称字段,因此您的数据库不确定引用的是哪个表。
了解有关 SQL 的更多信息
在 Django、Django Rest Framework 和 Django 的 ORM(对象关系映射器)之间,我们可以做很多事情,而无需深入研究 SQL。但是,当您遇到问题时,了解一些 SQL 约定会有所帮助(同样,不要假设您不知道,但是阅读此答案的一些人可能对此很陌生)。
这里,主要的一点是,虽然我们只能通过名称来引用字段,但是一旦我们处理多个同名的表,我们就需要使用点表示法。 table_name.field_name
以避免像您收到的错误。
试试 W3School 的interactive queriable database。他们也有一个tutorial。
【讨论】:
谢谢你的回答,我试过了。我收到(1054, "Unknown column 'api_switchesport.name' in 'field list'")
错误。但是您的回答让我知道问题是由排序引起的。如果我不使用'length'
进行排序,我不会收到错误消息。
我假设您的应用名称是 api,因为这是您使用的基本路线。如果您的应用名称不同,它将以不同的方式存储在您的数据库中。请查看我的编辑以及我们可以用来进一步诊断的代码。
我进行了重大修改,添加了有关在 Django 中调试 SQL 以解决此问题和未来查询/数据库问题的建议。【参考方案2】:
这是extra()
的众所周知的限制;它不会正确别名引用。我建议您不要使用 it should only be used as a last resort。
你应该使用annotate(Length)
annotate(
length=Length('name'),
).order_by('length', 'name')
https://docs.djangoproject.com/en/2.0/ref/models/database-functions/#length
或者只是将Length
传递给order_by
,如果它只是注释 用于订购目的
.order_by(Length('name'), name)
https://docs.djangoproject.com/en/2.0/ref/models/querysets/#order-by
【讨论】:
我从您的回答中学到了很多东西!我不想删除我的答案,因为当 OP 原始发布问题时,get_queryset(self):
代码没有被包括在内,所以我觉得我的答案仍然增加了调试过程的价值(我与 OP 一起做了很多工作找出问题出在哪里),但我编辑了我的答案,并认为你反映了你的答案提供的更好的建议(当然,赞成你的答案)。以上是关于django.db.utils.OperationalError:(1052,“字段列表中的列'名称'不明确”)的主要内容,如果未能解决你的问题,请参考以下文章