4

I have a class looking like the following:

class Sound(SoundJsonSerializer):
    def __init__(self, name, length):
        self.name = name
        self.length = length

where SoundJsonSerializer enabling my custom JSONEncoder to serialize this object into JSON:

{
    "name": "foobar",
    "length": 23.4
}

Now I want one of my requests to respond exactly with the above JSON.

@app.route('/sounds/<soundid>')
def get_sound(soundid):
    s = Sound("foobar", 23.4)
    return jsonify(s)

yields an error claiming s was not iterable which is true. How do I make the method return my wanted JSON?

I know I can do it by explicitly creating a dict from my Sound object like this:

    return jsonify({"name": s.name, "length": s.length})

But this seems really ugly to me. What's the preferred way to achieve my goal?

2
  • Actually, I would prefer the way that you deem "ugly". If you do this often enough, then perhaps make the creation of the dictionary into a function that takes the object and a list of strings representing the attributes you want included (or perhaps excluded) and create the dictionary (using dir() and getattr()). Commented Dec 19, 2013 at 20:09
  • 2
    Yeah this issue is pretty annoying, so I decided to patch Flask to make it work. Commented Oct 20, 2014 at 8:26

2 Answers 2

3

You could possibly try this work around:

class Sound():
    def __init__(self, name, length):
        self.name = name
        self.length = length

@app.route('/sounds/<soundid>')
def get_sound(soundid):
    s = Sound('foobar', 23.4)
    return jsonify(s.__dict__)
Sign up to request clarification or add additional context in comments.

2 Comments

This is not a good practice as it exposes all the class internals, not only the attributes he wants
@PaoloCasciello is right, there might only be a subset of attributes that I want in the JSON representation. That's what my custom JSONEncoder takes care of.
2

You can do this a couple of different ways. The safest way to ensure that you only return what you want is to do it like this:

class Sound():
    name = None
    length = None
    test = "Test"

    def __init__(self, name, length):
        self.name = name
        self.length = length

@admin_app.route('/sounds/<sound_id>')
def get_sound(sound_id):
    s = Sound('foobar', sound_id)
    return jsonify(vars(s))

By defining the name = None, length = None as part of the class level variables, you can use the vars() versus the __dict__

When you instantiate the class through the __init__, and set the variables there, the jsonify will only return what you set via the __init__.

Result with above code:

{
"length": "1",
"name": "foobar"
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.