2. JSON Serialization

2.1. JSON syntax

Format JSON jest podobny do zapisu dict w Python, ale różni się:

  • nie może być przecinka po ostatnim elemencie list
  • zawsze są stosowane podwójne cudzysłowia
  • true i false jest pisane małymi literami
  • zamiast None jest null

2.2. JSON Serialization of simple objects

2.2.1. Serializing to JSON

Code Listing 2.6. Serializing to JSON
import json


DATA = {
    'first_name': 'Pan',
    'last_name': 'Twardowski'
}

output = json.dumps(DATA)
print(output)
# '{"first_name": "Pan", "last_name": "Twardowski"}'

2.2.2. Deserializing from JSON

Code Listing 2.7. Deserializing from JSON
import json


DATA = '{"first_name": "Pan", "last_name": "Twardowski"}'

output = json.loads(DATA)
print(output)
# {
#     'first_name': 'Pan',
#     'last_name': 'Twardowski'
# }

2.3. Serializing datetime and date

2.3.1. Encoding datetime and date

Code Listing 2.8. Exception during encoding datetime
from datetime import datetime, date
import json


DATA = {
    'email': '[email protected]',
    'date': date(1961, 4, 12),
    'datetime': datetime(1969, 7, 21, 14, 56, 15),
}

output = json.dumps(DATA)
# TypeError: Object of type date is not JSON serializable
Code Listing 2.9. Encoding datetime and date
from datetime import datetime, date
import json


DATA = {
    'email': '[email protected]',
    'date': date(1961, 4, 12),
    'datetime': datetime(1969, 7, 21, 14, 56, 15),
}


def encoder(self, value):

    if isinstance(value, datetime):
        return value.strftime('%Y-%m-%dT%H:%M:%S.%fZ')
    elif isinstance(value, date):
        return value.strftime('%Y-%m-%d')


json.JSONEncoder.default = encoder

output = json.dumps(DATA)
print(output)
# '{"email": "[email protected]", "date": "1961-04-12", "datetime": "1969-07-21T14:56:15.000Z"}'

2.3.2. Decoding datetime and date

Code Listing 2.10. Simple loading returns str not datetime or date
import json


DATA = '{"email": "[email protected]", "date": "1961-04-12", "datetime": "1969-07-21T14:56:15.000Z"}'

output = json.loads(DATA)
print(output)
# {
#     'email': '[email protected]',
#     'date': '1961-04-12',
#     'datetime': '1969-07-21T14:56:15.000Z',
# }
Code Listing 2.11. Decoding datetime and date
from datetime import datetime, timezone
import json


DATA = '{"email": "[email protected]", "date": "1961-04-12", "datetime": "1969-07-21T14:56:15.000Z"}'


def decoder(obj):
    for key, value in obj.items():

        if key == 'datetime':
            dt = datetime.strptime(value, '%Y-%m-%dT%H:%M:%S.%fZ')
            obj['datetime'] = dt.replace(tzinfo=timezone.utc)

        elif key == 'date':
            dt = datetime.strptime(value, '%Y-%m-%d')
            obj['date'] = dt.replace(tzinfo=timezone.utc).date()

    return obj


output = json.loads(DATA, object_hook=decoder)

print(output)
# {
#     'email': '[email protected]',
#     'date': datetime.date(1961, 4, 12),
#     'datetime': datetime.datetime(1969, 7, 21, 14, 56, 15, tzinfo=datetime.timezone.utc),
# }

2.4. Class based encoders and decoders

2.4.1. Class based encoder

Code Listing 2.12. Class based encoder
from datetime import datetime, date
import json


DATA = {
    'email': '[email protected]',
    'date': date(1961, 4, 12),
    'datetime': datetime(1969, 7, 21, 14, 56, 15),
}


class JSONDatetimeEncoder(json.JSONEncoder):
    def default(self, value):

        if isinstance(value, datetime):
            return value.strftime('%Y-%m-%dT%H:%M:%S.%fZ')
        elif isinstance(value, date):
            return value.strftime('%Y-%m-%d')


output = json.dumps(DATA, cls=JSONDatetimeEncoder)

print(output)
# '{"email": "[email protected]", "date": "1961-04-12", "datetime": "1969-07-21T14:56:15.000Z"}'

2.4.2. Class based decoder

Code Listing 2.13. Class based decoder
from datetime import datetime, timezone
import json


DATA = '{"email": "[email protected]", "date": "1961-04-12", "datetime": "1969-07-21T14:56:15.000Z"}'


class JSONDatetimeDecoder(json.JSONDecoder):
    def __init__(self):
        super().__init__(object_hook=self.default)

    def default(self, obj):
        for key, value in obj.items():

            if key == 'datetime':
                dt = datetime.strptime(value, '%Y-%m-%dT%H:%M:%S.%fZ')
                obj['datetime'] = dt.replace(tzinfo=timezone.utc)

            elif key == 'date':
                dt = datetime.strptime(value, '%Y-%m-%d')
                obj['date'] = dt.replace(tzinfo=timezone.utc).date()

        return obj


output = json.loads(DATA, cls=JSONDatetimeDecoder)

print(output)
# {
#     'email': '[email protected]',
#     'date': date(1961, 4, 12),
#     'datetime': datetime(1969, 7, 21, 14, 56, 15, tzinfo=datetime.timezone.utc),
# }

2.5. Serializing objects

2.5.1. Encoding objects

Code Listing 2.14. Encoding objects to JSON
import json
from dataclasses import dataclass


@dataclass
class Address:
    street: str
    city: str
    state: str
    zipcode: str
    country: str


@dataclass
class Contact:
    first_name: str
    last_name: str
    addresses: tuple = ()


DATA = [
    Contact(first_name='Pan', last_name='Twardowski', addresses=(
        Address(street='2101 E NASA Pkwy', city='Houston', state='Texas', zipcode='77058', country='USA'),
        Address(street='', city='Kennedy Space Center', zipcode='32899', state='Florida', country='USA'),
        Address(street='4800 Oak Grove Dr', city='Pasadena', zipcode='91109', state='California', country='USA'),
        Address(street='2825 E Ave P', city='Palmdale', state='California', zipcode='93550', country='USA'),
    )),
    Contact(first_name='José', last_name='Jiménez'),
    Contact(first_name='Иван', last_name='Иванович', addresses=()),
]


class JSONObjectEncoder(json.JSONEncoder):
    def default(self, obj):
        result = obj.__dict__
        result['__type__'] = obj.__class__.__name__
        return result


output = json.dumps(DATA, cls=JSONObjectEncoder)

print(output)
# [{"first_name": "Pan", "last_name": "Twardowski", "addresses": [{"street": "2101 E NASA Pkwy", "city": "Houston", "state": "Texas", "zipcode": "77058", "country": "USA", "__type__": "Address"}, {"street": "", "city": "Kennedy Space Center", "state": "Florida", "zipcode": "32899", "country": "USA", "__type__": "Address"}, {"street": "4800 Oak Grove Dr", "city": "Pasadena", "state": "California", "zipcode": "91109", "country": "USA", "__type__": "Address"}, {"street": "2825 E Ave P", "city": "Palmdale", "state": "California", "zipcode": "93550", "country": "USA", "__type__": "Address"}], "__type__": "Contact"}, {"first_name": "Jos\u00e9", "last_name": "Jim\u00e9nez", "addresses": [], "__type__": "Contact"}, {"first_name": "\u0418\u0432\u0430\u043d", "last_name": "\u0418\u0432\u0430\u043d\u043e\u0432\u0438\u0447", "addresses": [], "__type__": "Contact"}]

2.5.2. Decoding objects

Code Listing 2.15. Decoding objects from JSON
import json
import sys
from dataclasses import dataclass


DATA = """[{"first_name": "Pan", "last_name": "Twardowski", "addresses": [{"street": "2101 E NASA Pkwy", "city": "Houston", "state": "Texas", "zipcode": "77058", "country": "USA", "__type__": "Address"}, {"street": "Florida", "city": "Kennedy Space Center", "state": "", "zipcode": "32899", "country": "USA", "__type__": "Address"}, {"street": "4800 Oak Grove Dr", "city": "Pasadena", "state": "California", "zipcode": "91109", "country": "USA", "__type__": "Address"}, {"street": "2825 E Ave P", "city": "Palmdale", "state": "California", "zipcode": "93550", "country": "USA", "__type__": "Address"}], "__type__": "Contact"}, {"first_name": "Jos\u00e9", "last_name": "Jim\u00e9nez", "addresses": [], "__type__": "Contact"}, {"first_name": "\u0418\u0432\u0430\u043d", "last_name": "\u0418\u0432\u0430\u043d\u043e\u0432\u0438\u0447", "addresses": [], "__type__": "Contact"}]"""


@dataclass
class Address:
    street: str
    city: str
    state: str
    zipcode: str
    country: str


@dataclass
class Contact:
    first_name: str
    last_name: str
    addresses: tuple = ()


class JSONObjectDecoder(json.JSONDecoder):
    def __init__(self):
        super().__init__(object_hook=self.default)

    def default(self, obj):
        type = obj.pop('__type__')
        cls = getattr(sys.modules[__name__], type)
        return cls(**obj)


output = json.loads(DATA, cls=JSONObjectDecoder)
print(output)
# [
#   Contact(first_name='Pan', last_name='Twardowski', addresses=[
#       Address(street='2101 E NASA Pkwy', city='Houston', state='Texas', zipcode='77058', country='USA'),
#       Address(street='', city='Kennedy Space Center', state='Florida', zipcode='32899', country='USA'),
#       Address(street='4800 Oak Grove Dr', city='Pasadena', state='California', zipcode='91109', country='USA'),
#       Address(street='2825 E Ave P', city='Palmdale', state='California', zipcode='93550', country='USA')]),
#   Contact(first_name='José', last_name='Jiménez', addresses=[]),
#   Contact(first_name='Иван', last_name='Иванович', addresses=[])
# ]

2.6. Pretty Printing JSON

$ DATA='[{"sepalLength":5.1,"sepalWidth":3.5,"petalLength":1.4,"petalWidth":0.2,"species":"setosa"},{"sepalLength":4.9,"sepalWidth":3,"petalLength":1.4,"petalWidth":0.2,"species":"setosa"}]'

$ echo $DATA | python -m json.tool
[
    {
        "sepalLength": 5.1,
        "sepalWidth": 3.5,
        "petalLength": 1.4,
        "petalWidth": 0.2,
        "species": "setosa"
    },
    {
        "sepalLength": 4.9,
        "sepalWidth": 3,
        "petalLength": 1.4,
        "petalWidth": 0.2,
        "species": "setosa"
    }
]
$ echo '{"sepalLength":5.1,"sepalWidth":3.5,}' | python -m json.tool
Expecting property name enclosed in double quotes: line 1 column 37 (char 36)
$ URL='https://raw.githubusercontent.com/AstroMatt/book-python/master/serialization/data/iris.json'
$ curl $URL |python -m json.tool

Alternatywy:

2.7. Assignments

2.7.1. Iris Serialize

  • Filename: json_iris_serialize.py
  • Lines of code to write: 30 lines
  • Estimated time of completion: 20 min
  • Input data: Code Listing 2.16.
  1. Z danych wydziel nagłówek i pomiary

  2. Na podstawie nagłówka przekonwertuj na List[dict]

    • klucz: nazwa z nagłówka
    • wartość: obserwacje
    DATA = [
        {'Sepal length': 5.8, 'Sepal width': 2.7, ...},
        {'Sepal length': 5.1, 'Sepal width': 3.5, ...},
        {'Sepal length': 5.7, 'Sepal width': 2.8, ...},
        ...
    ]
    
  3. Zapisz do pliku iris.json w formacie JSON

Code Listing 2.16. Iris Serialize
DATA = [
    ('Sepal length', 'Sepal width', 'Petal length', 'Petal width', 'Species'),
    (5.8, 2.7, 5.1, 1.9, 'virginica'),
    (5.1, 3.5, 1.4, 0.2, 'setosa'),
    (5.7, 2.8, 4.1, 1.3, 'versicolor'),
    (6.3, 2.9, 5.6, 1.8, 'virginica'),
    (6.4, 3.2, 4.5, 1.5, 'versicolor'),
    (4.7, 3.2, 1.3, 0.2, 'setosa'),
    (7.0, 3.2, 4.7, 1.4, 'versicolor'),
    (7.6, 3.0, 6.6, 2.1, 'virginica'),
    (4.9, 3.0, 1.4, 0.2, 'setosa'),
    (4.9, 2.5, 4.5, 1.7, 'virginica'),
    (7.1, 3.0, 5.9, 2.1, 'virginica'),
    (4.6, 3.4, 1.4, 0.3, 'setosa'),
    (5.4, 3.9, 1.7, 0.4, 'setosa'),
    (5.7, 2.8, 4.5, 1.3, 'versicolor'),
    (5.0, 3.6, 1.4, 0.3, 'setosa'),
    (5.5, 2.3, 4.0, 1.3, 'versicolor'),
    (6.5, 3.0, 5.8, 2.2, 'virginica'),
    (6.5, 2.8, 4.6, 1.5, 'versicolor'),
    (6.3, 3.3, 6.0, 2.5, 'virginica'),
    (6.9, 3.1, 4.9, 1.5, 'versicolor'),
    (4.6, 3.1, 1.5, 0.2, 'setosa'),
]
The whys and wherefores:
 
  • Serializacja danych
  • Korzystanie z biblioteki JSON
  • Konwersja typów
  • Praca z plikami

2.7.2. Iris deserialize

  • Filename: json_iris_deserialize.py
  • Lines of code to write: 30 lines
  • Estimated time of completion: 20 min
  • Input data: Code Listing 2.17.
  1. Dane z listingu poniżej skopiuj do pliku “iris.json”

    Code Listing 2.17. Iris dataset in JSON
    [{"sepalLength":5.1,"sepalWidth":3.5,"petalLength":1.4,"petalWidth":0.2,"species":"setosa"},{"sepalLength":4.9,"sepalWidth":3,"petalLength":1.4,"petalWidth":0.2,"species":"setosa"},{"sepalLength":4.7,"sepalWidth":3.2,"petalLength":1.3,"petalWidth":0.2,"species":"setosa"},{"sepalLength":4.6,"sepalWidth":3.1,"petalLength":1.5,"petalWidth":0.2,"species":"setosa"},{"sepalLength":5,"sepalWidth":3.6,"petalLength":1.4,"petalWidth":0.2,"species":"setosa"},{"sepalLength":5.4,"sepalWidth":3.9,"petalLength":1.7,"petalWidth":0.4,"species":"setosa"},{"sepalLength":4.6,"sepalWidth":3.4,"petalLength":1.4,"petalWidth":0.3,"species":"setosa"},{"sepalLength":5,"sepalWidth":3.4,"petalLength":1.5,"petalWidth":0.2,"species":"setosa"},{"sepalLength":4.4,"sepalWidth":2.9,"petalLength":1.4,"petalWidth":0.2,"species":"setosa"},{"sepalLength":4.9,"sepalWidth":3.1,"petalLength":1.5,"petalWidth":0.1,"species":"setosa"},{"sepalLength":7,"sepalWidth":3.2,"petalLength":4.7,"petalWidth":1.4,"species":"versicolor"},{"sepalLength":6.4,"sepalWidth":3.2,"petalLength":4.5,"petalWidth":1.5,"species":"versicolor"},{"sepalLength":6.9,"sepalWidth":3.1,"petalLength":4.9,"petalWidth":1.5,"species":"versicolor"},{"sepalLength":5.5,"sepalWidth":2.3,"petalLength":4,"petalWidth":1.3,"species":"versicolor"},{"sepalLength":6.5,"sepalWidth":2.8,"petalLength":4.6,"petalWidth":1.5,"species":"versicolor"},{"sepalLength":5.7,"sepalWidth":2.8,"petalLength":4.5,"petalWidth":1.3,"species":"versicolor"},{"sepalLength":6.3,"sepalWidth":3.3,"petalLength":4.7,"petalWidth":1.6,"species":"versicolor"},{"sepalLength":4.9,"sepalWidth":2.4,"petalLength":3.3,"petalWidth":1,"species":"versicolor"},{"sepalLength":6.6,"sepalWidth":2.9,"petalLength":4.6,"petalWidth":1.3,"species":"versicolor"},{"sepalLength":5.2,"sepalWidth":2.7,"petalLength":3.9,"petalWidth":1.4,"species":"versicolor"},{"sepalLength":6.3,"sepalWidth":3.3,"petalLength":6,"petalWidth":2.5,"species":"virginica"},{"sepalLength":5.8,"sepalWidth":2.7,"petalLength":5.1,"petalWidth":1.9,"species":"virginica"},{"sepalLength":7.1,"sepalWidth":3,"petalLength":5.9,"petalWidth":2.1,"species":"virginica"},{"sepalLength":6.3,"sepalWidth":2.9,"petalLength":5.6,"petalWidth":1.8,"species":"virginica"},{"sepalLength":6.5,"sepalWidth":3,"petalLength":5.8,"petalWidth":2.2,"species":"virginica"},{"sepalLength":7.6,"sepalWidth":3,"petalLength":6.6,"petalWidth":2.1,"species":"virginica"},{"sepalLength":4.9,"sepalWidth":2.5,"petalLength":4.5,"petalWidth":1.7,"species":"virginica"},{"sepalLength":7.3,"sepalWidth":2.9,"petalLength":6.3,"petalWidth":1.8,"species":"virginica"},{"sepalLength":6.7,"sepalWidth":2.5,"petalLength":5.8,"petalWidth":1.8,"species":"virginica"},{"sepalLength":7.2,"sepalWidth":3.6,"petalLength":6.1,"petalWidth":2.5,"species":"virginica"}]
    
  2. Odczytaj dane z pliku, i wyświetl je w formacie List[tuple]

  3. Pierwsza linijka ma zawierać nagłówek

  4. Kolejne linie mają mieć dane

The whys and wherefores:
 
  • Deserializacja danych
  • Korzystanie z biblioteki JSON
  • Konwersja typów
  • Praca z plikami

2.7.3. Date serialization

  • Filename: json_datetimes.py
  • Lines of code to write: 10 lines
  • Estimated time of completion: 15 min
  1. Skopiuj do swojego pliku strukturę danych Code Listing 2.18.
  2. Zapisz ją do pliku JSON
  3. Wczytaj ją z pliku JSON jako obiekty Pythona (ten sam efekt co na listingu)
The whys and wherefores:
 
  • Serializacja danych
  • Korzystanie z biblioteki JSON
  • Serializowanie zagnieżdżonych dat i dat z czasem
Code Listing 2.18. Sample Python data JSON
from datetime import datetime, date


DATA = {
    "astronaut": {
        "date": date(1961, 4, 12),
        "person": "[email protected]"
    },
    "flight": [
        {"datetime": datetime(1969, 7, 21, 14, 56, 15), "action": "landing"}
    ]
}

2.7.4. Serializing custom class to JSON

  • Filename: json_objects.py
  • Lines of code to write: 15 lines
  • Estimated time of completion: 20 min
  1. Skopiuj do pliku iris.json dane z listingu Code Listing 2.19.
  2. Stwórz klasy Setosa, Virginica, Versicolor
  3. Czytając dane z pliku twórz obiekty powyższych klas w zależności od wyniku pomiaru (pole “species”)
The whys and wherefores:
 
  • Serializacja danych
  • Korzystanie z biblioteki JSON
  • Serializowanie zagnieżdżonych obiektów
Code Listing 2.19. Sample Python data JSON
[
  {"sepalLength": 5.0, "sepalWidth": 3.6, "petalLength": 1.4, "petalWidth": 0.2, "species": "setosa"},
  {"sepalLength": 4.9, "sepalWidth": 3.1, "petalLength": 1.5, "petalWidth": 0.1, "species": "setosa"},
  {"sepalLength": 4.9, "sepalWidth": 3.0, "petalLength": 1.4, "petalWidth": 0.2, "species": "setosa"},
  {"sepalLength": 7.0, "sepalWidth": 3.2, "petalLength": 4.7, "petalWidth": 1.4, "species": "versicolor"},
  {"sepalLength": 4.6, "sepalWidth": 3.1, "petalLength": 1.5, "petalWidth": 0.2, "species": "setosa"},
  {"sepalLength": 6.5, "sepalWidth": 3.0, "petalLength": 5.8, "petalWidth": 2.2, "species": "virginica"},
  {"sepalLength": 7.1, "sepalWidth": 3.0, "petalLength": 5.9, "petalWidth": 2.1, "species": "virginica"},
  {"sepalLength": 6.7, "sepalWidth": 2.5, "petalLength": 5.8, "petalWidth": 1.8, "species": "virginica"},
  {"sepalLength": 5.2, "sepalWidth": 2.7, "petalLength": 3.9, "petalWidth": 1.4, "species": "versicolor"},
  {"sepalLength": 5.0, "sepalWidth": 3.4, "petalLength": 1.5, "petalWidth": 0.2, "species": "setosa"},
  {"sepalLength": 4.9, "sepalWidth": 2.4, "petalLength": 3.3, "petalWidth": 1.0, "species": "versicolor"},
  {"sepalLength": 6.5, "sepalWidth": 2.8, "petalLength": 4.6, "petalWidth": 1.5, "species": "versicolor"},
  {"sepalLength": 5.4, "sepalWidth": 3.9, "petalLength": 1.7, "petalWidth": 0.4, "species": "setosa"},
  {"sepalLength": 6.3, "sepalWidth": 3.3, "petalLength": 4.7, "petalWidth": 1.6, "species": "versicolor"},
  {"sepalLength": 6.4, "sepalWidth": 3.2, "petalLength": 4.5, "petalWidth": 1.5, "species": "versicolor"},
  {"sepalLength": 6.6, "sepalWidth": 2.9, "petalLength": 4.6, "petalWidth": 1.3, "species": "versicolor"},
  {"sepalLength": 5.8, "sepalWidth": 2.7, "petalLength": 5.1, "petalWidth": 1.9, "species": "virginica"},
  {"sepalLength": 6.3, "sepalWidth": 2.9, "petalLength": 5.6, "petalWidth": 1.8, "species": "virginica"},
  {"sepalLength": 7.6, "sepalWidth": 3.0, "petalLength": 6.6, "petalWidth": 2.1, "species": "virginica"},
  {"sepalLength": 5.1, "sepalWidth": 3.5, "petalLength": 1.4, "petalWidth": 0.2, "species": "setosa"},
  {"sepalLength": 7.3, "sepalWidth": 2.9, "petalLength": 6.3, "petalWidth": 1.8, "species": "virginica"},
  {"sepalLength": 4.7, "sepalWidth": 3.2, "petalLength": 1.3, "petalWidth": 0.2, "species": "setosa"},
  {"sepalLength": 6.9, "sepalWidth": 3.1, "petalLength": 4.9, "petalWidth": 1.5, "species": "versicolor"},
  {"sepalLength": 7.2, "sepalWidth": 3.6, "petalLength": 6.1, "petalWidth": 2.5, "species": "virginica"},
  {"sepalLength": 4.4, "sepalWidth": 2.9, "petalLength": 1.4, "petalWidth": 0.2, "species": "setosa"},
  {"sepalLength": 5.5, "sepalWidth": 2.3, "petalLength": 4.0, "petalWidth": 1.3, "species": "versicolor"},
  {"sepalLength": 4.6, "sepalWidth": 3.4, "petalLength": 1.4, "petalWidth": 0.3, "species": "setosa"},
  {"sepalLength": 6.3, "sepalWidth": 3.3, "petalLength": 6.0, "petalWidth": 2.5, "species": "virginica"},
  {"sepalLength": 4.9, "sepalWidth": 2.5, "petalLength": 4.5, "petalWidth": 1.7, "species": "virginica"},
  {"sepalLength": 5.7, "sepalWidth": 2.8, "petalLength": 4.5, "petalWidth": 1.3, "species": "versicolor"}
]

2.7.5. Deserialize data from GITHub

  • Filename: json_deserialize_github.py
  • Lines of code to write: 15 lines
  • Estimated time of completion: 20 min
  1. Za pomocą biblioteki requests pobierz dane z https://api.github.com/users
  2. Iterując po rekordach twórz obiekty klasy User
The whys and wherefores:
 
  • Deserializacja danych
  • Korzystanie z biblioteki JSON
  • Deserializacja zagnieżdżonych obiektów
  • Reprezentacja klas na podstawie danych otrzymanych przez API

2.7.6. Deserialize

  • Filename: json_deserialize_classes.py
  • Lines of code to write: 30 lines
  • Estimated time of completion: 30 min
  1. Po API dostajesz JSONa tak jak na listingu poniżej
  2. Iterując po rekordach twórz obiekty klasy Astronaut
  3. Sparsuj user_permissions i przedstaw je za pomocą listy klas
  4. Nazwa klasy to klucz w słowniku
  5. Są zawsze cztery pola: "add", "modify", "view", "delete"
  6. Jeżeli jakieś pole jest wymienione, to ma wartość True, jeżeli nie to False
The whys and wherefores:
 
  • Deserializacja danych
  • Korzystanie z biblioteki JSON
  • Deserializacja zagnieżdżonych obiektów
  • Reprezentacja klas na podstawie danych otrzymanych przez API
[{"model":"authorization.user","pk":1,"fields":{"password":"pbkdf2_sha256$120000$gvEBNiCeTrYa0$5C+NiCeTrYsha1PHogqvXNiCeTrY0CRSLYYAA90=","last_login":"1970-01-01T00:00:00.000Z","is_superuser":false,"username":"commander","first_name":"Иван","last_name":"Иванович","email":"","is_staff":true,"is_active":true,"date_joined":"1970-01-01T00:00:00.000Z","groups":[1],"user_permissions":[{"eclss":["add","modify","view"]},{"communication":["add","modify","view"]},{"medical":["add","modify","view"]},{"science":["add","modify","view"]}]}},{"model":"authorization.user","pk":2,"fields":{"password":"pbkdf2_sha256$120000$eUNiCeTrYHoh$X32NiCeTrYZOWFdBcVT1l3NiCeTrY4WJVhr+cKg=","last_login":null,"is_superuser":false,"username":"executive-officer","first_name":"José","last_name":"Jiménez","email":"","is_staff":true,"is_active":true,"date_joined":"1970-01-01T00:00:00.000Z","groups":[1],"user_permissions":[{"eclss":["add","modify","view"]},{"communication":["add","modify","view"]},{"medical":["add","modify","view"]},{"science":["add","modify","view"]}]}},{"model":"authorization.user","pk":3,"fields":{"password":"pbkdf2_sha256$120000$3G0RNiCeTrYlaV1$mVb62WNiCeTrYQ9aYzTsSh74NiCeTrY2+c9/M=","last_login":"1970-01-01T00:00:00.000Z","is_superuser":false,"username":"crew-medical-officer","first_name":"Melissa","last_name":"Lewis","email":"","is_staff":true,"is_active":true,"date_joined":"1970-01-01T00:00:00.000Z","groups":[1],"user_permissions":[{"communication":["add","view"]},{"medical":["add","modify","view"]},{"science":["add","modify","view"]}]}},{"model":"authorization.user","pk":4,"fields":{"password":"pbkdf2_sha256$120000$QmSNiCeTrYBv$Nt1jhVyacNiCeTrYSuKzJ//WdyjlNiCeTrYYZ3sB1r0g=","last_login":null,"is_superuser":false,"username":"science-data-officer","first_name":"Mark","last_name":"Watney","email":"","is_staff":true,"is_active":true,"date_joined":"1970-01-01T00:00:00.000Z","groups":[1],"user_permissions":[{"communication":["add","view"]},{"science":["add","modify","view"]}]}},{"model":"authorization.user","pk":5,"fields":{"password":"pbkdf2_sha256$120000$bxS4dNiCeTrY1n$Y8NiCeTrYRMa5bNJhTFjNiCeTrYp5swZni2RQbs=","last_login":null,"is_superuser":false,"username":"communication-officer","first_name":"Pan","last_name":"Twardowski","email":"","is_staff":true,"is_active":true,"date_joined":"1970-01-01T00:00:00.000Z","groups":[1],"user_permissions":[{"communication":["add","modify","view"]},{"science":["add","modify","view"]}]}},{"model":"authorization.user","pk":6,"fields":{"password":"pbkdf2_sha256$120000$aXNiCeTrY$UfCJrBh/qhXohNiCeTrYH8nsdANiCeTrYnShs9M/c=","last_login":null,"is_superuser":false,"username":"eclss-officer","first_name":"Harry","last_name":"Stamper","email":"","is_staff":true,"is_active":true,"date_joined":"1970-01-01T00:00:00.000Z","groups":[1],"user_permissions":[{"communication":["add","view"]},{"eclss":["add","modify","view"]},{"science":["add","modify","view"]}]}}]