How can I get JSON from nested python object
class simplobj:
def _init_(self,fname,lname,depart):
self.fname=fname
self.lname=lname
self.depart = depart
class jsonobj:
array = []
def _init_(self,time,listOfSimpleObj):
self.time = time
self.array = listofSimpleObj
class Main:
listOfSimpleObj =[]
sobj = simplobj("fname1","lname1","depart1")
listOfSimpleObj.append(sobj)
outputjsonobj = jsonobj(time,listOfSimpleObj)
output = json.dumps(outputjsonobj._dict_)
output: { "time" : "time", "array": [
{ "fname": "fname1", "lname": "lname1", "depart": "depart1"},
{ "fname": "fname2", "lname": "lname2", "depart": "depart2"},
{ "fname": "fname3", "lname": "lname3", "depart": "depart3"} ] }
You could create a json.JSONEncoder to specify how your classes should be serialized:
class MyEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, simplobj) or isinstance(obj, jsonobj):
return obj.__dict__
return json.JSONEncoder.default(self, obj)
...
output = json.dumps(outputjsonobj, cls=MyEncoder)
Related
I have a Django Application and want to convert a value from a string field which is comma separated to a key vaule pair and add it to a json data block.
class MyClass1(models.Model):
keywords = models.TextField(_('Keywords'), null=True, blank=True)
Example of list:
blue,shirt,s,summer,for women
The JSON data in my code
data = {
"name": self.name,
"type": self.type,
...
"keywords": []
}
I want to split the comma separated string of self.keywords and append it to the keywords field in my json, but as a array like this:
{
"name": keyword,
},
I do the split with the split function, but dont know how to create a key value pair as array and append to keywords.
Expected output:
data = {
"name": "Name of item",
"type": "Type of item",
...
"keywords": [
{
"name": "blue"
},
{
"name": "shirt"
},
...
]
}
You can work with .split():
data = {
'name': self.name,
'type': self.type,
# …
'keywords': [{'name': n} for n in self.keywords.split(',')],
}
It might however be better to work with a custom field. You can define such field with:
from django.db import models
class ListAsCharField(models.Field):
def __init__(self, separator=',', *args, **kwargs):
self.separator = separator
super().__init__(*args, **kwargs)
def get_db_prep_value(self, value, connection, prepared=False):
if isinstance(value, (str, type(None))):
value = self.separator.join(str(x) for x in value)
return super().get_db_prep_value(value, connection, prepared)
def from_db_value(self, value, expression, connection):
if isinstance(value, str):
return value.split(self.separator)
def to_python(self, value):
if isinstance(value, str):
value = value.split(self.separator)
return value
then you can use this in the model to automatically do the wrapping/unwrapping from a list:
class MyClass1(models.Model):
keywords = ListAsCharField(
max_length=256, verbose_name=_('Keywords'), null=True, blank=True
)
Then you can process this with:
data = {
'name': self.name,
'type': self.type,
# …
'keywords': [{'name': n} for n in self.keywords],
}
i want to create an object of My_Class and want to tell it with a string what dictionary to get. Is there a better way than to do it with if?
object_dictionary = {
"car" : "some_car",
"house" : "some_house",
"animal" : "some_animal"
}
class My_Class:
def __init__(self, string):
if string == "object_dictionary":
self.dictionary = object_dictionary
obj = My_Class("object_dictionary")
If I want to choose between more dictionaries this will be inconvenient. How can I do this?
object_dictionary = {
"car" : "some_car",
"house" : "some_house",
"animal" : "some_animal"
}
class My_Class:
def __init__(self, string):
self.dictionary = string
obj = My_Class("object_dictionary")
Use dict of dicts. See below
dicts = {
"this_dictionary": {
"car": "some_car",
"house": "some_house",
"animal": "some_animal"
},
"that_dictionary": {
"12": "ttt"
}
}
class MyClass:
def __init__(self, dict_name):
self.dictionary = dicts.get(dict_name, {})
obj = MyClass("that_dictionary")
I have a class A where it stores a collection of variables of type B, how can I serialize class A to JSON properly?
example:
class A:
def __init__(self):
self.b_collection = []
#...
class B:
def __init__(self):
# ...
pass
and add instances of B into the collection:
a = A()
a.b_collection = [B(), B(), B()]
when I try to serialize a with json.dumps(a) I get this error: Object of type A is not JSON serializable.
Is there a way to specify how to encoder should encode that class?
something like
def __encode__(self, encoder):
encoder.start_obj()
encoder.add_property('name', self.value)
encoder.add_property('age', self.age)
encoder.end_obj()
which would return something like
{
name: 'Tomer',
age: '19'
}
You can extend json.JSONEncoder to define how to serialize your objects. The default method of your subclass will take a Python object as an argument. You can return a new object that is (hopefully) encodable, or pass the object on to the parent in hopes that it knows how to encode the object.
For example,
class A:
def __init__(self):
self.b_collection = []
class B:
def __init__(self, name, age):
self.name = name
self.age = age
class ABEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, A):
return {'__A__': obj.b_collection}
elif isinstance(obj, B):
return {'__B__': obj.__dict__}
return super().default(obj)
a = A()
a.b_collection.append(B("Tomer", "19"))
a.b_collection.append(B("Bob", "21"))
a.b_collection.append(B("Alice", "23"))
print(json.dumps(a, cls=ABEncoder, indent=4))
would produce
{
"__A__": [
{
"__B__": {
"name": "Tomer",
"age": "19"
}
},
{
"__B__": {
"name": "Bob",
"age": "21"
}
},
{
"__B__": {
"name": "Alice",
"age": "23"
}
}
]
}
Note that you can handle A and B separately; you don't have to first encode the B objects before returning the encodable form of A; the B objects will be encoded later when the list itself is encoded.
The extra objects make it easier to write a decoder; you don't have to make it this complicated if you don't want to be able to decode the JSON to an instance of A. Instead, you can just define
class ABEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, A):
return obj.b_collection
elif isinstance(obj, B):
return obj.__dict__
return super().default(obj)
to get
[
{
"name": "Tomer",
"age": "19"
},
{
"name": "Bob",
"age": "21"
},
{
"name": "Alice",
"age": "23"
}
]
Maybe data classes can help:
from dataclasses import asdict, dataclass
from typing import List
import json
#dataclass
class Person:
name: str
age: str
#dataclass
class Group:
persons: List[Person]
data = [
{'name': 'Tomer', 'age': '19'},
{'name': 'Ivan', 'age': '20'}
]
persons = [Person(**person) for person in data]
group = Group(persons=persons)
assert json.dumps(asdict(group)) == '{"persons": [{"name": "Tomer", "age": "19"}, {"name": "Ivan", "age": "20"}]}'
persons = [asdict(person) for person in group.persons]
assert persons == [{"name": "Tomer", "age": "19"}, {"name": "Ivan", "age": "20"}]
assert json.dumps(persons) == '[{"name": "Tomer", "age": "19"}, {"name": "Ivan", "age": "20"}]'
I got a class with arrays of classes as properties
class classToJson():
def __init__(self, name, image, objects1, objects2):
self.name = name
self.image = image
self.boolean = True
self.objects1 = objects1
self.objects2 = objects2
def __repr__(self):
return json.dumps(self.__dict__)
object1 and object2 class looks like this:
class object1():
value1 = 1
value2 = 0
class objects2:
def __init__(self, name, value):
self.name = name
self.value = value
This is how I create my json of the class.
obj2 = [...]
parsedObject = classToJson(name, image, [object1], obj2)
file = open("{}.json".format(name),"w")
file.write("[{}]".format(parsedObject.__repr__()))
file.close()
This works if I only use name, image and boolean in the class but when I include objects1 or objects2 I get the TypeError: Object of type 'type' is not JSON serializable. Why?
The json schema I want to accomplish:
[
{
"name": "name",
"image": "image",
"boolean": true,
"objects1": [
{
"value1": 1,
"value2": 0
}
],
"objetcs2": [
{
"name": "name",
"value": "value"
}
]
}
]
Just use the built in json.dump like so
import json
with open('file.json') as f:
json.dump([{
'name': name,
'image': image,
'boolean": True,
'object1': object1,
'object2': object2
}], f)
In Flask-Restplus, I need to model an attribute value that maybe either a list of strings or a list of objects.
That is it can look like this:
{
'my_attribute': [
'value1',
'value2'
]
}
or it can look like the following:
{
'my_attribute': [
{
'name': 'value1',
'foo': 'something'
},
{
'name': 'value2',
'foo': 'something else'
}
]
}
How should I model that in Flask-Restplus’ api.model?
I've just figured this out myself. In short, create a custom field class that emits its own JSON schema. In turn the schema uses the oneOf type to specify that this is either a string or an object.
from flask_restplus import fields
element_object = api.model('Element_Object', {
'name': fields.String(),
'foo': fields.String()
})
class StringOrObjectElement(fields.Nested):
__schema_type__ = ['string','object']
def output(self, key, obj):
if isinstance(obj, str):
if key == 'name':
return obj
else:
return 'default_value'
return super().output(key, obj)
def schema(self):
schema_dict = super().schema()
schema_dict.pop('type')
nested_ref = schema_dict.pop('$ref')
schema_dict['oneOf'] = [
{
'type': 'string'
},
{
'$ref': nested_ref
}
]
return schema_dict
root_object = api.model('Root_Object', {
'my_attribute': fields.List(fields.StringOrObjectElement(element_object))