1

basically I've got a booking class with fields each declared manually. I am curious if theres a more neat solution for the given task.

class Booking:
    def __init__(self, json_data):
        self.referenceNumber = json_data["referenceNumber"]
        self.fromDate = json_data["fromDate"]
        self.preferredDate1 = json_data["preferredDate1"]
        self.preferredTimeFrom = json_data["preferredTimeFrom"]
        self.time = json_data["time"]
        self.partySize = json_data["partySize"]
        self.budgetAmountTotal = json_data["budgetAmountTotal"]
        self.budgetAmountPerPerson = json_data["budgetAmountPerPerson"]
        self.budgetCurrencySign = json_data["budgetCurrencySign"]
        self.venueName = json_data["venueName"]
        self.venueId = json_data["venueId"]
        self.cityName = json_data["cityName"]
        self.clientName = json_data["clientName"]
        self.clientContactName = json_data["clientContactName"]
        self.status = json_data["status"]
        self.statusText = json_data["statusText"]
        self.assigneeId = json_data["assigneeId"]
        self.assignee = json_data["assignee"]
        self.lastAction = json_data["lastAction"]
        self.inquiryChannel = json_data["inquiryChannel"]
        self.venueDateFormat = json_data["venueDateFormat"]
        self.bookingId = json_data["bookingId"]
        self.inquiryHold = json_data["inquiryHold"]
        self.isSpaceSelectedForHolds = json_data["isSpaceSelectedForHolds"]
        self.id = json_data["id"]

bonus if i am not given an unresolved reference warning when I am calling for the attribute.

Saba
  • 416
  • 3
  • 14
  • 2
    Does this answer your question? [How to convert JSON data into a Python object?](https://stackoverflow.com/questions/6578986/how-to-convert-json-data-into-a-python-object) – matszwecja Oct 18 '22 at 07:33

4 Answers4

1

A simple self.__dict__.update(json_data) might do the trick.

treuss
  • 1,913
  • 1
  • 15
  • This will work for level 1 dictionary but not for nested. Like `d["name"]["first_name"]` – Deepak Tripathi Oct 18 '22 at 07:42
  • It'll work for the example in the OP. For nested JSON, you will get a dictionary, so obj.name["first_name"] will work, but not obj.name.first_name. – treuss Oct 18 '22 at 07:51
  • messing with `__dict__` directly is a bad idea. What if at some point a custom `__set_attr__` added? This code would bypass it – Nikolay Zakirov Oct 18 '22 at 08:23
  • this works fine, but its giving me unresolved reference warning considering pycharm doesnt know specific attribute exists and I am unsure if i should keep my code like that and ignore the warning. – Saba Oct 18 '22 at 08:36
0

How about this?

def set_attr_from_json(obj, json_data):
    for key, value in json_data.items():
        setattr(obj, key, value)
        
class Booking:                
    def __init__(self, json_data):
        set_attr_from_json(self, json_data)
Nikolay Zakirov
  • 1,505
  • 8
  • 17
0

Given the code in the question, access to attributes would be, for example, in the style of:

Booking().fromDate

However, if you don't mind accessing the value by its key name then you can greatly simplify the code as follows:

class Booking:
  def __init__(self, json_data):
    self._json = json.data
  def __getitem__(self, key):
    return self._json.get(key)

Then (for example)...

pd = {'fromDate': '2022/10/18'}

print(Booking(pd)['fromDate'])
DarkKnight
  • 19,739
  • 3
  • 6
  • 22
0

Since you want to control how your class attributes should be built, I think you should use metaclass like this

import json
from types import SimpleNamespace

class BookingMeta(type):
    def __call__(self, json_data):
        obj = super().__call__(json_data)
        obj = json.loads(json.dumps(json_data), object_hook=lambda d: SimpleNamespace(**d))
        return obj

class Booking(metaclass=BookingMeta):                
    def __init__(self, json_data):
        pass


b = Booking({"name": {"first_name": "hello", "last_name": "world"}, "age": 23, "sub": ["maths", "Science"]})
print(b.name.first_name)
print(b.age)
#hello
#23
Deepak Tripathi
  • 3,175
  • 1
  • 8
  • 21