def parse_simple_token(token, manager, related_models, left=False, sibling_token=None): """ Parse the simple token dict. :param token: a dict with 'tokenType'=='PROPERTY'|'NUMBER'|'STRING' and 'tokenValue'==a value of the corresponding type. :param manager: The django model manager :param related_models: Related models joined to the manager model :param left: Default False. If set then the token is an assignee and shouldn't be wrapped in an F() expression if it's a property :param sibling_token: the left side token if we are evaluating a right side token (left=False) """ if token["tokenType"] == "PROPERTY": # Resolve the field path in case it's relative to a joined related_model field_path = resolve_field_path_via_geographies( "__".join(token["tokenValue"].split(".")), manager, related_models ) # Wrap in an F() expression if field is a right-side argument (the thing being assigned) return field_path if left else F(field_path) elif token["tokenType"] == "NUMBER": return float(token["tokenValue"]) elif token["tokenType"] in ["STRING", "null", "undefined"]: if token["tokenType"] in ["null", "undefined"]: # Accept the 'null' or 'undefined' tokenType to mean None value = None else: value = token["tokenValue"] if sibling_token and sibling_token.get("tokenType", None) == "PROPERTY": # If we are evaluating a right-side token, inspect the sibling_token (the left-side token) # to find out what type the property is. This only matters for Dates and Times # where we need to modify the resolved right-side value to be have a time zone # if one isn't specified # Resolve the possibly chained property field_path = resolve_field_path_via_geographies( "__".join(sibling_token["tokenValue"].split(".")), manager, related_models ) field = resolve_field_of_path(manager, field_path) if not field: return parser_lookup = {DateTimeField: parse_datetime, DateField: parse_date, TimeField: parse_time} if isinstance(field, (DateTimeField, DateField, TimeField)): date_time = parser_lookup[field.__class__](value) if not date_time and isinstance(field, DateTimeField): # Accept dates without times for datetimes date_time = timezone.utc.localize( datetime.combine(parser_lookup[DateField](value), datetime.min.time()) ) if isinstance(field, (DateTimeField, TimeField)) and not date_time.tzinfo: # Default the timezone to UTC return date_time.replace(tzinfo=timezone.utc) return date_time return value # TODO handle booleans and other types return token["tokenType"]
def map_result_path(field_path): # Get the field and the optional related model field, related_model = resolve_field_of_path(self, field_path, True) field_class_path = full_module_path(field.__class__) # Return return [field_path, field_class_path if\ not return_related_models else\ (field_class_path, full_module_path(related_model) if related_model else None)]
def parse_simple_token(token, manager, related_models, left=False, sibling_token=None): """ Parse the simple token dict. :param token: a dict with 'tokenType'=='PROPERTY'|'NUMBER'|'STRING' and 'tokenValue'==a value of the corresponding type. :param manager: The django model manager :param related_models: Related models joined to the manager model :param left: Default False. If set then the token is an assignee and shouldn't be wrapped in an F() expression if it's a property :param sibling_token: the left side token if we are evaluating a right side token (left=False) """ if token['tokenType'] == 'PROPERTY': # Resolve the field path in case it's relative to a joined related_model field_path = resolve_field_path_via_geographies('__'.join(token['tokenValue'].split('.')), manager, related_models) # Wrap in an F() expression if field is a right-side argument (the thing being assigned) return field_path if left else F(field_path) elif token['tokenType'] == 'NUMBER': return float(token['tokenValue']) elif token['tokenType'] in ['STRING', 'null', 'undefined']: if token['tokenType'] in ['null', 'undefined']: # Accept the 'null' or 'undefined' tokenType to mean None value = None else: value = token['tokenValue'] if sibling_token and sibling_token.get('tokenType', None) == 'PROPERTY': # If we are evaluating a right-side token, inspect the sibling_token (the left-side token) # to find out what type the property is. This only matters for Dates and Times # where we need to modify the resolved right-side value to be have a time zone # if one isn't specified # Resolve the possibly chained property field_path = resolve_field_path_via_geographies('__'.join(sibling_token['tokenValue'].split('.')), manager, related_models) field = resolve_field_of_path(manager, field_path) if not field: return parser_lookup = {DateTimeField: parse_datetime, DateField: parse_date, TimeField: parse_time} if isinstance(field, (DateTimeField, DateField, TimeField)): date_time = parser_lookup[field.__class__](value) if not date_time and isinstance(field, DateTimeField): # Accept dates without times for datetimes date_time = timezone.utc.localize(datetime.combine(parser_lookup[DateField](value), datetime.min.time())) if isinstance(field, (DateTimeField, TimeField)) and not date_time.tzinfo: # Default the timezone to UTC return date_time.replace(tzinfo=timezone.utc) return date_time return value # TODO handle booleans and other types return token['tokenType']