From 0cff58749946e977be230ad63a47774e6113cbcb Mon Sep 17 00:00:00 2001 From: Mikhail Mezyakov Date: Tue, 12 Mar 2024 21:28:17 -0700 Subject: [PATCH] Parse nested objects (#666) Summary: In the current version nested objects are not handled correctly. For example, we want to retrieve Ads for the campaign using only one request. With this fix, we'll be able to make requests like: ``` campaigns = account.get_campaigns(fields=['name,ads{id,name,status}']) campaign = campaigns[0] ``` In this example nested Ads objects will be available as ``` campaign.get('ads') ``` Pull Request resolved: https://github.com/facebook/facebook-python-business-sdk/pull/666 Reviewed By: mengxuanzhangz Differential Revision: D54815751 Pulled By: stcheng fbshipit-source-id: f23299bc168c33e485830ce500d8c8841cfbaf02 --- facebook_business/adobjects/objectparser.py | 35 ++++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/facebook_business/adobjects/objectparser.py b/facebook_business/adobjects/objectparser.py index 9ad4885c..d8466f5a 100644 --- a/facebook_business/adobjects/objectparser.py +++ b/facebook_business/adobjects/objectparser.py @@ -9,6 +9,7 @@ ) from facebook_business.adobjects.abstractobject import AbstractObject + class ObjectParser: """ Parser for API response @@ -39,30 +40,48 @@ def __init__( self._custom_parse_method = custom_parse_method self._api = api - def parse_single(self, response): + def parse_single(self, response, override_target_class=None): if self._custom_parse_method is not None: return self._custom_parse_method(response, self._api) + from .ad import Ad + from .adpreview import AdPreview + from .adset import AdSet + from .campaign import Campaign + data = response if 'data' in response and isinstance(response['data'], dict): data = response['data'] elif 'images' in response and not isinstance(data['images'], list): _, data = data['images'].popitem() - if 'campaigns' in data: - _, data = data['campaigns'].popitem() - elif 'adsets' in data: - _, data = data['adsets'].popitem() - elif 'ads' in data: - _, data = data['ads'].popitem() + + subfields = ( + ('campaigns', Campaign), + ('adsets', AdSet), + ('ads', Ad), + ('previews', AdPreview), + ) + for subfield, _class in subfields: + if subfield not in data: + continue + + data[subfield] = [ + self.parse_single( + item, override_target_class=_class + ) for item in data[subfield]['data'] + ] + if 'success' in data: del data['success'] + target_class = override_target_class or self._target_class + if self._reuse_object is not None: self._reuse_object._set_data(data) return self._reuse_object elif self._target_class is not None: return AbstractObject.create_object(self._api, data, - self._target_class) + target_class) else: raise FacebookBadObjectError( 'Must specify either target class calling object' +