3

I have these list objects that are callable by name. They have number values that users can input. how would I turn each of those lists to form that chart js can render? I tried with this: Django Queryset to dict for use in json but could not get it working. Getting "Object of type QuerySet is not JSON serializable". Chart js would need to have own line for each of those list and show the values in those lines. This is how far I got with the link in views:

First I get all of users lists:

user_lists = List.objects.filter(user=user)

Then I get number values for each list

list_data = {}
for list in user_lists:
    list_data[list.name] = DataItem.objects.filter(list=list)

Here is where I get stuck when I should convert these lists to something that chart.js can understand..

list_data_json = json.dumps(list_data, cls=DjangoJSONEncoder)

btw am I in the right tracks to put this conversion to views, right? or does it belong somewhere else?

Dont know if these are needed but here are models for these lists and the data items in them:

class List(models.Model):
    name = models.CharField(max_length=100, default="")
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='lists')

def __str__(self):
    return self.name

class Meta:
    unique_together = ['name', 'user']


class DataItem(models.Model):
    data = models.IntegerField(default=0)
    list = models.ForeignKey(List, on_delete=models.CASCADE, related_name='data_items')

EDIT output query set looks like this (this is what json.dumps is trying to read i quess):

<QuerySet [{'name': 'squat', 'data_items__data': 1}, {'name': 'deadlift', 'data_items__data': 55}, {'name': 'Chest', 'data_items__data': None}, {'name': 'asd', 'data_items__data': 444}, {'name': 'asd', 'data_items__data': 32342}, {'name': 'asd', 'data_items__data': 42342}]>

And for me that looks good, there is a list of lists and list has a name "squats" and then values. But getting this error again "'QuerySet' object is not callable"

2 Answers2

3

If you know what fields you want to pass to chart.js, you can do a specific values() query to get a dictionary, which you can easily serialize with json.dumps, more or less like this:

user_lists = (List.objects
    .filter(user=user)
    .select_related('user')
    .prefetch_related('data_items')
    .values('user__username', 'data_items__data')  # all fields you need
)

list_data_json = json.dumps(list(user_lists))
Endre Both
  • 5,540
  • 1
  • 26
  • 31
  • Duh ! Should have thought of it (facepalm). – bruno desthuilliers Mar 14 '19 at 11:39
  • I got error "'List' object is not callable" @Endre Both – Joonas Mykkänen Mar 14 '19 at 11:44
  • 1
    @JoonasMykkänen you must have used `list` as a variable name (probably instead of `user_lists`) which shadows the builtin `list` type. – bruno desthuilliers Mar 14 '19 at 11:50
  • The solution is [not far off](https://stackoverflow.com/questions/31087111/typeerror-list-object-is-not-callable-in-python)... – Endre Both Mar 14 '19 at 11:54
  • Edited post! @brunodesthuilliers – Joonas Mykkänen Mar 14 '19 at 12:54
  • @JoonasMykkänen "XXX object is not callable" errors means that you've shadowed a function or class name with another variable. If you name your queryset `list` (ie : `list = List.objects.filter(...)`) then try to call `list` (ie : json.dumps(list(something))`, then of course you get this kind of error since the name `list` doesn't refer to the builtin `list` type but to whatever you assigned to it. Note that this is basic Python stuff (ok, basic python gotcha if you come from a language where functions and classes are not objects). – bruno desthuilliers Mar 14 '19 at 14:08
1

despite what one could expect, DjangoJSONEncoder doesn't handle querysets nor models instances (see here for the types DjangoJSONEncoder deals with) - this part is actually handled by the serializer itself, but a serializer expects a Queryset and not a dict of querysets.

IOW, you will have to write your own encoder (based on DjangoJSONEncoder) to handle querysets and models (hint: someobj.__dict__ returns the object's attributes as a dict, which you can filter out to remove irrelevant django stuff like _state)

bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118
  • I have zero knowledge on javascript, only using since need those charts.. Could it be done with each queryset separately with serializer? If possible how? @bruno desthuilliers – Joonas Mykkänen Mar 14 '19 at 11:33
  • This has nothing to do with Javascript actually (json is NOT javascript, it's a text format based on js syntax). And you cannot jsonify querysets separately, put them in the dict and jsonify the whole dict, as querysets would be doubly encoded (so the result would not be valid json). The solution I describe - which is _really_ easy to setup actually) is the one correct solution. – bruno desthuilliers Mar 14 '19 at 11:38
  • or actually just use Endre Both's solution which is much simpler and smarter xD – bruno desthuilliers Mar 14 '19 at 11:42
  • well I'm new to jsons and stuff so I would not know :D – Joonas Mykkänen Mar 14 '19 at 11:47