19

I'm trying to use the ValuesQuerySet feature in Django to limit the number of fields returned from query to only those I need. I would like to serialize this data set a JSON object However, Django keeps throwing an error. Below I've included my code and the error I receive:

objectList = ConventionCard.objects.values('fileName','id').filter(ownerUser = user)
data = serializers.serialize('json', objectList)
return HttpResponse(data, mimetype='application/javascript')

The Error:

Exception Type:     AttributeError
Exception Value:    'dict' object has no attribute '_meta'
Exception Location:     C:\Python27\lib\site-packages\django\core\serializers\base.py in serialize, line 41

Thanks !

cezar
  • 11,616
  • 6
  • 48
  • 84
Karthik Ramachandran
  • 11,925
  • 10
  • 45
  • 53
  • Why are you using `values()`? That makes `dict` objects which can't easily be serialized. – S.Lott Jul 06 '11 at 18:27
  • 3
    I don't want my entire object. I just want two fields. Values seems to be the way to do this. Is there a better way? – Karthik Ramachandran Jul 06 '11 at 18:28
  • Since `values` doesn't work, saying that it "seems to be the way to do this" can't be true. If you want just two fields, please **update** the question say that very, very clearly. It's not clear in the question. – S.Lott Jul 06 '11 at 18:34
  • 1
    @S.Lott Values does exactly what it's suppose to do: it returns a subset of the fields. What doesn't work is the serialization of the resulting object. – Karthik Ramachandran Jul 06 '11 at 18:39
  • Since your code does **not** work, `values()` does not work. Simple logic. The code doesn't work, something must be wrong. What's wrong is using `values()`. It gets an error. That means is does not work for the thing you are trying to do. Please **update** the question to be very clear on the thing you are trying to do. – S.Lott Jul 06 '11 at 18:56
  • 8
    @S.Lott "I'm trying to use the ValuesQuerySet feature in Django **to limit the number of fields returned from query to only those I need**." It was clear in the question. – Jordan Reiter Nov 04 '11 at 15:00
  • @JordanReiter: "It was clear in the question". Before making statements like this, please include the words "to me, but not to you." I'm sorry to contradict you, but it was not clear to at least one other person. – S.Lott Nov 06 '11 at 15:26
  • I'm honestly not sure how else to interpret the text that I quoted, but I'll agree to disagree. – Jordan Reiter Nov 07 '11 at 16:31
  • @JordanReiter: "agree to disagree"? How is that possible? I'm stating a fact. You may not be able to find another interpretation. You're smart. At least one person here is not smart and actually found the question actually confusing. Please do not state "It was clear in the question" when you have at least one person to whom that does not apply. Please be very careful about statements which are clearly false from the evidence provided. I found the question confusing. Please don't tell me that I'm wrong. I really was confused. – S.Lott Nov 08 '11 at 03:22
  • @S.Lott Sorry, I wondered whether you might have scanned the question and missed that part of it. I do that a lot myself. I thought you were saying they had omitted that detail in the question. If instead you found that sentence confusing then obviously, yes, the question was unclear to you. No offense meant. – Jordan Reiter Nov 08 '11 at 14:55
  • @JordanReiter: "I thought you were saying". It's often better to ask than to assume. It's often good to avoid making blanket statements about other people's ability to comprehend something. What doesn't confuse you can really confuse other people; it's often helpful to consider that other people have different abilities than yours. – S.Lott Nov 11 '11 at 14:59
  • 1
    @S.Lott True. I'm reminded of a poster once that said, `Instead of saying "This doesn't make sense!" you should say "I don't understand."` We all should work towards understanding. – Jordan Reiter Nov 11 '11 at 15:55

4 Answers4

35

Cast the ValuesQuerySet to a list first:

query_set = ConventionCard.objects.values('fileName','id').filter(ownerUser = user)

list(query_set)

Removing the values call as suggested by ars causes the manager to pull all columns from the table, instead of only the two you need.

Aaron
  • 829
  • 2
  • 9
  • 15
18

Try subsetting the fields in your values list through the serialize method using a QuerySet instead:

from django.core import serializers
objectQuerySet = ConventionCard.objects.filter(ownerUser = user)
data = serializers.serialize('json', objectQuerySet, fields=('fileName','id'))
andilabs
  • 22,159
  • 14
  • 114
  • 151
ars
  • 120,335
  • 23
  • 147
  • 134
  • 16
    Not ideal because the query is pulling all column data out when it only needs the two fields. – Aaron Feb 09 '12 at 04:38
  • when i was trying this thing, i noticed that, serializers.serialize `fields` option, did not select the column/fields of related models. Anybody faced the same? – Ashish Sep 28 '14 at 01:07
14

I continued to get a dict object has no attribute _meta error when using the list() method above. However I found this snippet that does the trick

def ValuesQuerySetToDict(vqs):
    return [item for item in vqs]

# Usage
data = MyModel.objects.values('id','title','...','...')
data_dict = ValuesQuerySetToDict(data)
data_json = simplejson.dumps(data_dict)
Henrik Andersson
  • 45,354
  • 16
  • 98
  • 92
7wonders
  • 1,639
  • 1
  • 17
  • 34
  • 2
    Module `simplejson` was [removed](https://docs.djangoproject.com/en/1.7/releases/1.5/#django-utils-simplejson) in Django 1.5. The alternative is to simply `import json` and then use `json.dumps(data_dict)` and the answer is as expected. – Jeel Shah Dec 07 '17 at 22:34
  • This needs to be higher because the serializer has two flaws. 1. rest_framework also has serialzer, so you have to do from django.core import serializers as emily, and the second is the serializer doesnt' work on a queryset like this: statement_line.objects.select_related('ae').values('ae__opp_own', 'cur','ae_id').annotate(tots=Sum('amt')) – Henrietta Martingale Oct 17 '19 at 22:15
1

Just to add a few details I've found:

When I tried @ars answer specifying the fields, like:

s_logs = serializers.serialize("json", logs, fields=('user', 'action', 'time'))

I get this:

[{"pk": 520, "model": "audit.auditlog", "fields": {"user": 3, "action": "create", "time":"2012-12-16T12:13:45.540"}}, ... ]

Which was not a simple serialization of the values as I wanted it.

So I tried the solution proposed by @Aaron, converting the valuesqueryset to a list, which didn't work the first time because the default encoder cannot deal with floats or datetime objects.

So I used @Aaron solution but using the JSON encoder that is used by django's serializer (DjangoJSONEncoder) by passing it as a kwarg to simplejson.dumps(), like this:

s_logs = list(logs.values('user', 'ip', 'object_name', 'object_type', 'action', 'time'))

return HttpResponse(simplejson.dumps( s_logs, cls=DjangoJSONEncoder ), mimetype='application/javascript')
AJJ
  • 7,365
  • 7
  • 31
  • 34
  • If you are using simplejson > 2.1, take a look at this issue: https://github.com/simplejson/simplejson/issues/37 Given that issue, one might have to subclass `simplejson.JSONEncoder` instead of `json.JSONEncoder` – defbyte Jun 11 '13 at 17:54