python - django.db.utils.OperationalError:(1052,“字段列表中的列'名称'不明确”)
问题描述
在我的 Django 项目中,当我查询数据时出现以下错误:
django.db.utils.OperationalError:(1052,“字段列表中的列'名称'不明确”)
使用:
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
我的物理服务器模型:
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)
...
编辑-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
编辑-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
到目前为止,我们发现问题是因为name
当我尝试按其length
in排序时该字段不明确PhysicalServerListAPIView
:
return qs.extra(select={'length':'Length(name)'}).order_by('length', 'name')
如果我直接退货qs
,我不会有这个问题。
解决方案
问题在于您的 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 上的简短讨论,很容易理解。
- 如果您可以仅使用 ORM 的函数来完成您想要完成的工作,那就去做吧!
- 如果需要,请返回
.annotate()
以向查询添加额外信息 - 如果您需要做的事情不能使用上述工具,那么使用
.extra()
- 如果即使这样也失败了,请使用手动 SQL 查询
.raw()
当然,一切都可以使用手动 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 如何在“通过直接连接到您的数据库进行调试”部分中实际命名您的表的建议。
同样,按照西蒙的建议,我认为您甚至不需要在您的视图中使用 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。
记录所有查询
请参阅有关记录所有查询的这个问题(以及查看发生了什么查询的有趣工具)
显示一个查询
要仅显示一个问题查询,您可以执行以下操作(我包含了您的示例,但将 qs.extra 替换为您可能需要调试的另一个查询):
有关更多详细信息,请参见此处:django orm,如何查看(或记录)已执行的查询?
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 中调试
我在这里没有太多使用这种方法,但这是你开始的方式
- 通过键入启动 shell
python manage.py shell
from django.db import connection
- 测试 ORM python 命令。看玩 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 为我们做出了这个决定,我们可能不知道表的实际名称!
测试您从“调试一个查询”步骤中获得的查询。
选择(长度(api_switchesport.name))作为
length
,api_physicalserver
。id
,api_physicalserver
.name
,api_physicalserver
.switches_id
,api_physicalserver
.physical_server_model_id
,api_physicalserver
.switchesport_id
从api_physicalserver
INNER JOINapi_switchesport
ON
(api_physicalserver
.switchesport_id
=api_switchesport
.id
)
WHERE 开始api_switchesport
。bandwidth
LIKE '%10%' ORDER BYlength
ASC;对我来说,此查询成功执行,但如果它为您抛出错误,请尝试修改内容。特别是字段名称
api_switchesport.name
。最初name
和我一样,因为几乎所有表都有一个名称字段,所以您的数据库不确定引用哪个表。
了解有关 SQL 的更多信息
在 Django、Django Rest Framework 和 Django 的 ORM(对象关系映射器)之间,我们可以做很多事情,而无需深入研究 SQL。但是,当您遇到问题时,了解一些 SQL 约定会有所帮助(同样,不要假设您不知道,但是阅读此答案的一些人可能对此很陌生)。
在这里,主要的一点是,虽然我们只能通过名称来引用字段,但是一旦我们处理多个同名的表,我们就需要使用点表示法。table_name.field_name
以避免像您收到的错误。
推荐阅读
- javascript - why does it not 'add to cart' when I click add to cart?
- excel - COUNTIF 跨多个“重命名”工作表
- asp.net - 在单页应用程序中添加服务器端代码
- r - Rmarkdown YAML 标头中的作者从属关系,使用 rticles
- ruby-on-rails - 如何将 ajax 附加到 Rails 中的关注/取消关注链接
- android - ListView:如何在单击 ListView 中的按钮时转到新活动?
- c++ - Visual Studio 17 调试属性未导出到模板
- user-interface - 如何在 GUI 中实现我的 while 循环以使用 Visual Studio 在 C/C++ 中保持按键
- python - 是否可以仅使用哈希来查找文件和文件路径
- asp.net - 编译错误:C:\Users\mhomes\AppData\Local\Temp\8\Temporary ASP.NET Files\ 行:90