django queryset 返回“类名对象”而不是 DB 值

Posted

技术标签:

【中文标题】django queryset 返回“类名对象”而不是 DB 值【英文标题】:django queryset returns "classname object" instead of DB values 【发布时间】:2014-01-27 01:58:24 【问题描述】:

我对 django 查询集有疑问。

型号:

class Rooms(models.Model,):
room_state = models.CharField(max_length=255, choices=[('emptyReady', 'empty'), ('emptyWaiting4Clean', 'clean ready'), ('busy', 'busy')])
room_type = models.IntegerField()
room_number = models.IntegerField()

我可以通过输入 python shell 来检查查询集的工作情况:

for d in Rooms.objects.filter(room_state="emptyReady", id='1'):    print(d)

在我的数据库中有表Rooms_rooms,里面有列room_state,如果我们对数据库进行查询:

SELECT room_state FROM Rooms_rooms where id = 1

返回值为emptyReady

但是当我使用查询集(如上面的示例)时,我总是得到:Rooms object

我做错了什么?我尝试在所有 WEB 中搜索答案 3 小时,现在我的耐心已经结束,所以我指望你们 ;)

【问题讨论】:

【参考方案1】:

这里:

Rooms.objects.filter(room_state="emptyReady", id='1')

返回Room 对象的查询集。

现在,如果你想要一个特定的值:

Rooms.objects.filter(room_state="emptyReady", id='1').values_list('room_state', flat=True)

阅读更多values_list here

或者:

for d in Rooms.objects.filter(room_state="emptyReady", id='1'):    print(d.room_state)

另一种方法是在class Room 上指定__unicode__ attribute

class Rooms(models.Model,):
    room_state = models.CharField(max_length=255, choices=[('emptyReady', 'empty'), ('emptyWaiting4Clean', 'clean ready'), ('busy', 'busy')])
    room_type = models.IntegerField()
    room_number = models.IntegerField()

    def __unicode__(self):
        return u'%s' % self.room_state

如果print d 被调用,这应该打印room_state

【讨论】:

【参考方案2】:

如果我理解,您正在尝试使用 Django 模拟以下查询:

SELECT room_state FROM Rooms_rooms where id = 1

鉴于您的模型,使用 Django,这可以通过发出:

Rooms.object.filter(room_state='emptyReady', id=1).values('room_state')

values() function 在 Django 1.2 版本(如果不是更早版本)中可用,它允许您仅选择那些您需要查询的字段。这比获取完整模型要快得多,因为它只为您提供包含选定字段的字典。

请注意,在您的代码中,您将 id 作为字符串而不是数字发送。此外,像 filter()values() 这样的函数永远不会返回集合,而是一个 Django 对象,您需要对其进行迭代以获取值。因此,最后您需要执行以下操作:

Rooms.object.filter(room_state='emptyReady', id=1).values('room_state')[0]['room_state']

这是故意对delay the effective work until it is truly needed进行的。

【讨论】:

【参考方案3】:

更新和完善@karthikr 的答案...

如果您尝试获取查询集并将其作为上下文传递给模板,然后在循环中迭代,例如:

(在views.py中)

# The manytomanyfield named subscribers in the Feed object points to the userprofile object which has a onetoonefield relationship with the user object
# [...]
queryset = Feed.objects.filter(subscribers=request.user.userprofile)
        context = 
                    "result_list"    : queryset,
        
        return render(request, "subscriptions/subscriptions.html", context)

(在 subscriptions.html 中)

# [...]
    % for instance in result_list %
        <p>  instance.pk  |---> <a href=''> instance.url </a> </p>
    % endfor %
# [...]

你会得到错误:

'Feed' object has no attribute '__name__'

当更改模板以显示 result_list 而不使用 for 循环时,例如:

# [...]
 result_list 
# [...]

我看到了与 OP 相同的输出(这是渲染器输出的):

<QuerySet [<Feed 'https://news.ycombinator.com/rss'>

在我的例子中是Feed object 而不是Rooms object

最初尝试循环遍历result_list 时,当模板渲染器认为字符串 Feed 是查询集的列或对象本身的实例时,就会出现错误,然后尝试确定调用它的内容在类似字典的数据结构中。

我不知道为什么在我的情况下 Feed.objects.filter() 或在 OP 的情况下 Rooms.objects.filter() 决定包含不带引号的类名,从而混淆模板渲染器。

我的解决方案是将我的查询更改为:

queryset = Feed.objects.filter(subscribers=request.user.userprofile).values_list('pk','url', named=True)

使用named=True 对能够在模板中单独处理列值很重要(例如 instance.pk )。使用上面的查询和如上所示的subscriptions.html 模板中的for-loop,渲染顺利进行:

1 |---> https://news.ycombinator.com/rss

【讨论】:

以上是关于django queryset 返回“类名对象”而不是 DB 值的主要内容,如果未能解决你的问题,请参考以下文章

在 Django 查询中提供 LIMIT 参数而不获取 QuerySet 的一部分

django queryset“包含”列表,而不是字符串

查询集 QuerySet

Django queryset values_list 是不是返回一个列表对象?

Django开发博客系统(05-QuerySet的使用)

django“类名”对象显示而不是名称