Django (JSONField) and tastypie
Asked Answered
M

4

7

I have a table into mysql that is the type TextField (django) by using the JSONField. This is how my model looks

from django.db import models
from json_field import JSONField

class Model(models.Model):
   obj     = JSONField()

The value I send via tastypie is

json_string = '{"data":"value"}'

Into the database I can see

{"data":"value"}

But when retrive the data with curl I get something like this

"{u'data': u'value'}"

What I can do to not have the python u'field' representation into the tastypie's output ?

thanks!

Misplace answered 17/1, 2013 at 19:5 Comment(2)
found what the problem was - the field was serialized as unicode from database and was sent as is by tastypie - to fix it I used the hydrate method on the Resource in 'load' it as a python data structure and send it over to tastypie.Misplace
It would be good if you shared the code of your solution in an answer to this question. Then please mark it as the accepted answer.Fashion
B
5

I fixed this issue like so:

def dehydrate_user_inputs(self, bundle):
    requirement = Requirement.objects.get(pk = bundle.obj.pk)
    user_inputs = json.dumps(requirement.user_inputs)
    return user_inputs

My JSONField is named user_inputs. Requirement is the model that it belongs to.

I feel weird doing a Query here when Tastypie has already done so for me, but, this works. I'd love if there are better solutions.

Brandeebranden answered 5/4, 2013 at 21:50 Comment(2)
You don't need to do the db query, as your Requirement object is in bundle.obj already. You can simplify your solution to <code> def dehydrate_user_inputs(self, bundle): return json.dumps(bundle.obj.user_inputs) </code>Sheehan
@Sheehan I believe your comment is incorrect (at least in tastypie 0.11.1). By the time you get to dehydration, the JSON object has already been converted to unicode (I assume by tastypie). Thus, to solve this at the point of dehydration you need to re-read it as kvnn says. See my answer for another approach (tackling it at point of hydration).Mayemayeda
M
5

The error you're seeing is caused by Tastypie treating the JSONField like a TextArea and calling str() on the object JSONField returns before returning it to the caller.

Another approach is to use fields.ApiFields for the JSONField. This works because fields.ApiFields does not perform any conversions on either the way in (hydrate()) or way out (convert()). This is exactly what we want - the underlying JSONField will convert the JSON object to a string for persistence on the way in and recreate the object from the string on the way out. Thus, tastypie does not need to do anything. My code looks a bit like this (class/variable names based on OP's example) -

class JSONField(fields.apiField):
    """ Wrapper over fields.apiField to make what we're doing here clear """
    pass

class MyModelResource(ModelResource):
    obj = JSONField('obj')
Mayemayeda answered 14/5, 2015 at 21:57 Comment(0)
S
4

Use DictField:

obj = fields.DictField(attribute='obj')
Spinose answered 6/8, 2014 at 6:32 Comment(1)
Goes to show, it's always worth scrolling down and looking at the other answers on StackOverflow. This was a great answer. I've used obj = fields.ListField(attribute='obj') before, but that was for array like data, this was exactly what I needed for more dict like data.Maori
A
1

I was running into similar problems where my unicode strings would be returned in a weird format in the API (I think the raw encoded strings were returned as opposed to the actual utf-8 characters).

Anyway instead of using the dehydrate method and re-doing the query, you are better off with a custom serializer in your resources.

This is what I used:

class JSONSerializer(Serializer):
    '''using the standard json library for better unicode support,
       also note django.utils.simplejson, used in the standard Tastypie serializer, 
       is set for depreciation'''

    def to_json(self, data, options=None):
        options = options or {}
        data = self.to_simple(data, options)
        return json.dumps(data)

then in your resources:

class PlaceResource(ModelResource):
    class Meta:
        queryset = Place.objects.all()
        resource_name = 'place'
        serializer = JSONSerializer()
Attalie answered 3/10, 2013 at 10:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.