[Django]-Django queryset returns "classname object" instead of DB values

7👍

Here:

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

returns a queryset of Room objects.

Now, if you want a specific value:

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

Read more on values_list here

Alternatively:

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

Another way is to specify a __unicode__ attribute on class Room

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

This should prin room_state value if print d is called

0👍

If I understand, you are trying to simulate the following query with Django:

SELECT room_state FROM Rooms_rooms where id = 1

Given your models, with Django, this can be achieved by issuing:

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

The values() function is available in Django since version 1.2 (if not earlier) and allows you to select only those fields you will need to query for. This is considerably faster than obtaining the complete model as it is only giving you a dictionary with the selected fields.

Note in your code you was sending the id as a string, not a number. Furthermore, functions like filter() or values() never return the collection but a Django object that you need to iterate over in order to get the values. So, finally you need to do something like:

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

This is done intentionally to delay the effective work until it is truly needed.

👤Salva

0👍

Update to and refinement of @karthikr ‘s answer…

If you’re trying to take a queryset and pass it as context to a template to then iterate through in a loop such as:

(in 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)

(in subscriptions.html)

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

You will get the error:

'Feed' object has no attribute '__name__'

When changing the template to show result_list without the for-loop such as:

# [...]
{{ result_list }}
# [...]

I saw a the same output as the OP (this is what the renderer outputted):

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

In my case it was Feed object instead of Rooms object.

When originally trying to loop through result_list, the error arose when the template renderer thought the string Feed was a column of the queryset or the instance of an object in and of itself, and then tried to determine what to call it in a dictionary-like data structure.

I have no idea why Feed.objects.filter() in my case or Rooms.objects.filter() in the OP’s case, decides to include the class name without quotes thus confusing the template renderer.

The solution for me was to change my query to:

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

Using named=True is important to be able to address the column values individually within the template (e.g. {{ instance.pk }}). With the above query and the for-loop in subscriptions.html template as shown above, the rendering goes through without a hitch:

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

Leave a comment