def filter(self, obj, library: Library = None): filter_func = None if library: filter_func = Obj.getattr(library.filters, self.filter_name, None, execute_callable=False) if not filter_func or not callable(filter_func): filter_func = Obj.getattr(defaultfilters, self.filter_name, None, execute_callable=False) if not filter_func or not callable(filter_func): filter_func = Obj.getattr(humanize, self.filter_name, None, execute_callable=False) if not filter_func or not callable(filter_func): raise ValueError('Invalid filter "%s"' % self.filter_name) if self.has_param(): return filter_func(obj, self.filter_param) return filter_func(obj)
def prep_select_optgroups(cls, the_list, opt_groups: list, value_attr, display_attr, none_value_label): """ Prep list to be use as a choice for the ChoiceField eg. sensor_choices = Lst.prep_select_optgroups(sensors, ['facility.name', 'zone.name'], 'id', 'sensor_name', _('Unassigned Sensors')) :param the_list: ValueQuerySet, QuerySet or list :param opt_groups: the group column/attr name or index :param value_attr: the option value :param display_attr: the option display text :return: """ groups = Lst.tuple_multi_group_by(the_list, none_value_label, opt_groups) if groups: result = [] for tp, arr in groups.items(): og_header = ' > '.join(tp) og_list = [] for row in arr: og_list.append(( Obj.getattr(row, value_attr), Obj.getattr(row, display_attr), )) result.append(( og_header, tuple(og_list), )) return tuple(result) return groups
def stage_audit_dict(cls, form): """ Call the model default 'get_audit_dict()' function to prepare for the audit stage data. :type form: Form|ModelForm :param form: """ instance = Obj.getattr(form, 'instance', None) if instance and instance.pk and Obj.has_func(instance, 'get_audit_dict'): instance._staged_data_point = instance.get_audit_dict()
def get_display(obj, attr_name): try: display_name = 'get_%s_display' % attr_name result = Obj.getattr(obj, display_name, None) if result is None: result = Obj.getattr(obj, attr_name, None) return result except: return None
def diff(cls, old_dict: dict, new_dict: dict, excludes=None): """ Compare two diff :param old_dict: :param new_dict: :param excludes: :return: """ try: from django_lazifier2.utils.builtin_types.obj import Obj except ImportError: Obj = sys.modules[__package__ + '.Obj'] if not isinstance(old_dict, dict): old_dict = Obj.get_dict(old_dict) or OrderedDict() if not isinstance(new_dict, dict): new_dict = Obj.get_dict(new_dict) or OrderedDict() result = OrderedDict() if not old_dict: for k, v in new_dict.items(): if excludes is None or k not in excludes: result[k + '_new'] = v return result for k, v in old_dict.items(): if excludes is None or k not in excludes: if isinstance(v, dict): result[k] = Dct.diff(v, new_dict.get(k, {}), excludes=excludes) continue if k not in new_dict: result[k + '_removed'] = v elif v != new_dict[k]: result[k + '_old'] = v result[k + '_new'] = new_dict[k] for k, v in new_dict.items(): if excludes is None or k not in excludes: if k not in old_dict: result[k + '_added'] = v return result
def get_display_name(cls, model: Model, field_name, default_value=None): field_key = Obj.getattr(model, field_name) if field_key is None: return default_value field = model._meta.get_field(field_name) choices = Obj.getattr(field, 'choices') if choices is None: return default_value for k, v in choices: if k == field_key: return v return default_value
def default(self, o): try: if isinstance(o, ValuesQuerySet) or isinstance(o, QuerySet): return [x for x in o] elif isinstance(o, JsonSerializer): return o.get_json_dict() elif isinstance(o, Model): return Obj.get_dict(o) elif isinstance(o, RawJsonString): placeholder = '[$RawJson-%s]' % uuid.uuid4() self.__raw_json_replacement[placeholder] = o.get_json() return placeholder elif isinstance(o, tzinfo): return str(o) elif isinstance(o, Decimal): return float(o) elif isinstance(o, Enum): return o.value elif isinstance(o, Promise): # translation proxy return str(o) elif isinstance(o, FieldFile): return o.name elif isinstance(o, bytes): return o.decode('utf-8', 'replace') elif PhoneNumber and isinstance(o, PhoneNumber): return o.as_national except Exception: pass return str(o)
def get_dict(cls, model: models.Model, filter_list=None, exclude_list=None, verbose_key=False, related_fields: list=None, related_names: list=None, key_maps: dict=None, get_display=False): """ Extract the values from the instance of the model, if the fields is specified then remove other fields not in the list. :type related_fields: list|None :param model: The model :param filter_list: :param exclude_list: :param verbose_key: get the verbose of the field name, ie name would be _('Name') :param related_fields: merge the related model into the this result dict :param related_names: just get the name of the related model instead fo the entire model like related_fields field name or tuple (field_name, the_field_contain_the_name) eg. ['facility', 'zone', ('sensoralarmmap_set', 'alarm_alert_link.name')] :param key_maps: change the keys of the dict to diff value { 'old_key1': 'new_key1', ... } :param get_display: if a get_<name>_display exist, use that to get the verbose name :return: :rtype: dict """ values = Obj.get_dict(model, filter_list=filter_list, exclude_list=exclude_list, verbose_key=verbose_key, get_display=get_display) rel = Mdl.get_related_models(model, filter_list=filter_list, exclude_list=exclude_list, verbose_key=verbose_key, related_fields=related_fields) if rel: values.update(rel) names = Mdl.get_related_model_names(model, related_names) if names: values.update(names) values = Dct.key_maps(values, key_maps) return values
def get_initial(cls, data, form: ModelForm, prefix=''): """ Extract data from post to put it in form.initial :param data: dict|request.GET|request.POST|request.REQUEST :param form: :param prefix: :return: """ if not data: return OrderedDict() data = Obj.get_dict(data) if prefix: # the Form put a dash between the prefix and the name # eg. field=name, prefix=alert it becomes alert-name prefix += '-' result = OrderedDict() fields = list(form.base_fields.keys()) for k, v in data.items(): if not prefix or k.startswith(prefix): k = k.replace(prefix, '') if k in fields: result[k] = v return result
def group_by(cls, the_list, group, none_value_label='None', flat=False): """ Group the list by the group specified. eg. Lst.group_by(seats, 'zone.name', 'do not belong to a zone') => { 'zone1': [seat1, seat2] 'zone2': [seat7, seat8] 'do not belong to a zone': [seat3, seat4, seat5] } :param the_list: :param group: {str} name of the attribute, support dot notation group_by(persons, 'contact.phone') :param none_value_label: the value of the column specified is None then use this label as the key. :param flat: if true only take the last item for each group and put it in the result dict :rtype: dict """ result = OrderedDict() for row in the_list: col_value = Obj.getattr(row, group, None) if col_value is None: col_value = none_value_label if not flat and col_value not in result: result[col_value] = [] if flat: result[col_value] = row else: result[col_value].append(row) return result
def get_related_model_names(cls, model: models.Model, related_names: list=None): """ Extract name from foreign keys, foreign and m2m fields eg. { facility_id: 10, facility_name: 'Trenton', zone_id:, zone_name:, ... } :param model: :param related_names: either foreign key field name or a tuple (field_name, 'the-field-contain-the-name') :return: """ if not related_names: return OrderedDict() related_fields = related_names result = OrderedDict() for rf in related_names: named_field = None if isinstance(rf, tuple): rf, named_field = rf rel_field = Obj.getattr(model, rf, None) if rel_field and isinstance(rel_field, Manager): value_list = [cls.get_id_name_pair(md, named_field=named_field) for md in rel_field.all()] result[rf] = value_list else: result.update(cls.get_id_name_pair(rel_field, named_field=named_field, prefix=rf)) return result
def d(obj, header='', indent=2, **kwargs): """ Var dumps :param obj: the object you want to print :param indent: indent the json output :param header: the text in front of the printout of the object :param kwargs: any custom argument to mark the name or key related to the object """ custom_param = '' if kwargs: custom_param = ' (%s)' % ', '.join( ['{}={}'.format(k, v) for k, v in kwargs.items()]) if type(obj) is str or type(obj) is int or type(obj) is float: if header: print('{}{} -> {}'.format(header, custom_param, str(obj))) else: print(str(obj)) return if not isinstance(obj, list) and not isinstance(obj, dict): obj = Obj.get_dict(obj) if header: print('{}{} -> '.format(header, custom_param)) print(json.dumps(obj, cls=JsonEncoder, skipkeys=True, indent=indent))
def get_related_models(cls, model: models.Model, filter_list=None, exclude_list=None, verbose_key=False, related_fields=None): if not related_fields: return OrderedDict() result = OrderedDict.fromkeys(related_fields, None) for rf in related_fields: rel_field = Obj.getattr(model, rf, None) if rel_field: if isinstance(rel_field, Manager): values = [] for itm in rel_field.all(): values.append(Mdl.get_dict(itm, filter_list, exclude_list, verbose_key)) result[rf] = values else: result[rf] = Obj.get_dict(rel_field) return result
def build_list(the_list, attr_name): """ Extract attr from each item in the list :param the_list: :param attr_name: attribute name support .dot notation (eg. list_of_people|build_list:"contact.phone" :return: list """ return [Obj.getattr(x, attr_name, None) for x in the_list]
def get_features(cls, query_set: QuerySet, geometry_field: str, primary_key='pk', filter_list=None, exclude_list=None): """ Convert queryset to a geojson FeatureCollection string. :param query_set: The model QuerySet (ie after filters or .all()) :param geometry_field: The field name contains the geometry (point, line, polygon, multipolygon, etc.) :param primary_key: The name of the primary key field :param filter_list: Which fields to include as the "properties" of the feature. :param exclude_list: Which fields to exclude as the "properties" of the feature. :return: """ template = '''{ "type": "FeatureCollection", "features": [%s] } ''' feature_list = [] sequential_id = 1 for f in query_set: properties = Obj.get_dict(f, filter_list, exclude_list) properties.pop(geometry_field, None) geometry = Obj.getattr(f, geometry_field) feature = dict(type="Feature", geometry=RawJsonString(geometry.geojson), properties=properties) feature['id'] = Obj.getattr(f, primary_key, sequential_id) feature_json = Json.to_json(feature) feature_list.append(feature_json) sequential_id += 1 features = '' if feature_list: features = ','.join(feature_list) return defaultfilters.mark_safe(template % features)
def create(self, manager: str = None): model_manager = self.model.objects if manager: model_manager = Obj.getattr(self.model, manager) for i in range(self.qty): record = self.model(**self._get_values()) self.data_list.append(record) if len(self.data_list) >= self.batch_size: self._bulk_insert(model_manager) self._bulk_insert(model_manager)
def str_join(cls, lst, separator=', ', value_attr: str = None): if not lst: return '' str_list = [] for itm in lst: if value_attr is not None: itm = Obj.getattr(itm, value_attr) itm = str(itm) str_list.append(itm) return separator.join(str_list)
def get_list(cls, qs: QuerySet): """ Return a list of a dict of each row :param qs: :return: """ result = [] for m in qs: result.append(Obj.get_dict(m)) return result
def to_json(cls, qs: QuerySet, related_list: list = None): """ Convert QuerySet to json eg. QrSt.to_json(sensor_objects, ['zone', 'facility.name', 'sensor__name'] :param qs: :param related_list: by default no related object is included, this explicitly tell which fields to fetch. :return: """ model_list = [] for m in qs: model_dict = Obj.get_dict(m) if related_list: for rl in related_list: rl = rl.replace('__', '.') attrs = rl.split('.') if attrs: first_attr = attrs.pop(0) cur_obj = Obj.getattr(m, first_attr) cur_dict = Obj.get_dict(cur_obj) model_dict[first_attr] = cur_dict for att, is_last in last_iter(attrs): if cur_obj is None: break nxt = Obj.getattr(cur_obj, att) cur_dict[att] = Obj.get_dict(nxt) cur_obj = nxt if is_last and isinstance(cur_obj, Manager): cur_dict[att] = QrSt.get_list(cur_obj.all()) else: cur_dict = cur_dict[att] model_list.append(model_dict) return Json.to_json(model_list)
def get_attr(obj, attr_name): """ Return the index of the list/dict :param obj: :param attr_name: supports the dot notation (eg. person|index:"contact.phone" where contact is attribute of person) :return: """ try: result = Obj.getattr(obj, attr_name, None) return result except: return None
def get_unique(cls, the_list, default_value=None, unique_attr=None): """ Get a list of unique values in the list, default_value is [] if default_value is set to None. :param the_list: :param default_value: if none value is [] :param unique_attr: select your own unique attribute (in case when the object is unhashable or you want your own attr) :rtype list """ if default_value is None: default_value = [] if not the_list: return default_value try: # Src: http://stackoverflow.com/questions/480214 # /how-do-you-remove-duplicates-from-a-list-in-python-whilst-preserving-order # Src: http://www.peterbe.com/plog/uniqifiers-benchmark if unique_attr is None: added_list = set() add_to_added_list = added_list.add # this static ref for performance reason return [ x for x in the_list if not (x in added_list or add_to_added_list(x)) ] result = [] existed_item = { } # dict is much faster than list when checking existence of a key for itm in the_list: key = Obj.getattr(itm, unique_attr) if key not in existed_item: result.append(itm) existed_item[key] = None return result except Exception as ex: log_exception(ex) return default_value
def get_id_name_pair(cls, instance: models.Model, named_field=None, prefix=''): """ Get id and name of a model. :param instance: instance of a model :param named_field: if you want to use non-standard named field, eg. name_field="nick_name" :param prefix: prefix this name to the result key. eg. { facility_id:, facility_name: } :return: :rtype: dict """ if prefix: prefix += '_' if not instance: return { prefix + 'id': None, prefix + 'name': str(None), } name_attrs = ['name', 'sensor_name', 'username'] if named_field: print(named_field) name_attrs = [named_field] + name_attrs try: for attr in name_attrs: name = Obj.getattr(instance, attr, 'NOT_FOUND!') if name != 'NOT_FOUND!': return { prefix + 'id': instance.pk, prefix + 'name': name, } except: pass return { prefix + 'id': instance.pk, prefix + 'name': str(instance), }
def join_by(the_list, options): """ Join the list. Usage: facilities|join_by:" ,zone.name" => facility1 facility2 facilities|join_by:", ,zone.name" => facility1, facility2 :param the_list: :param options: comma separated "{separator}, {attribute.inner_attribute}". :return: string """ if not the_list: return '' assert options, 'join_by: Arguments cannot be emptied.' if isinstance(the_list, Manager): the_list = the_list.all() elif callable(the_list): the_list = the_list.__call__() separator, attr = options.rsplit(',', 1) attr = attr.strip() return separator.join([Obj.getattr(itm, attr, '').__str__() for itm in the_list])
def get_json_dict(self): """ The dict equivalent of the json object. """ return Obj.get_dict(self, self.json_includes, self.json_excludes)
def test_get_attr(self): not_found = 'Not Found!' class Test: def __init__(self, a, b, other_test=None): self.a = a self.b = b self.other_test = other_test my_obj = { 'hello': 'hello world', 'obj': { 'int': 10, 'arr': [7, 0, 3, 2, 5], 'none': None, } } sub = Test('sub', 'class') parent = Test('parent class', 99, sub) self.assertEqual(Obj.getattr(my_obj, 'obj.arr', not_found), my_obj['obj']['arr']) self.assertEqual(Obj.getattr(my_obj, 'obj.arr.4', not_found), 5) self.assertEqual(Obj.getattr(my_obj, 'obj.arr.7', not_found), not_found) self.assertEqual(Obj.getattr(my_obj, 'obj.int', not_found), 10) self.assertEqual(Obj.getattr(my_obj, 'obj.none', not_found), None) self.assertEqual(Obj.getattr(my_obj, 'hello', not_found), my_obj['hello']) self.assertEqual(Obj.getattr(sub, 'a', not_found), sub.a) self.assertEqual(Obj.getattr(sub, 'b', not_found), sub.b) self.assertEqual(Obj.getattr(sub, 'other_test', not_found), sub.other_test) self.assertEqual(Obj.getattr(parent, 'a', not_found), parent.a) self.assertEqual(Obj.getattr(parent, 'b', not_found), parent.b) self.assertEqual(Obj.getattr(parent, 'other_test', not_found), sub) self.assertEqual(Obj.getattr(parent, 'other_test.a', not_found), sub.a) self.assertEqual(Obj.getattr(parent, 'other_test.b', not_found), sub.b) self.assertEqual( Obj.getattr(parent, 'other_test.other_test', not_found), sub.other_test)
def as_table(data, filter_param=None): """ Turn queryset or list row_dict into a table. :param data: queryset|list of [row_dict] :param filter_param: comma separated list of column. Syntax: queryset|as_table:'include_me, !not_include, include2' eg. users|as_table:'!age, !password' eg. group|as_table:'name, group_count' :return: """ if not data: return None result = [] filter_list = [] exclude_list = [] model = Obj.getattr(data, 'model', None, False) if filter_param: filter_param_list = Lst.strip_string(filter_param.split(',')) for the_filter in filter_param_list: assert isinstance(the_filter, str) if the_filter.startswith('!'): exclude_list.append(the_filter[1:]) else: filter_list.append(the_filter) if isinstance(data, dict): sub_tables = {} for key, row in data.items(): if isinstance(row, list): sub_tables[key] = as_table(row, filter_param) continue row_dict = Obj.get_dict(row, filter_list, exclude_list, verbose_key=True, get_display=True) result.append(row_dict) if sub_tables: context = {'sub_tables': sub_tables} html = render_to_string('lazifier/table_filter/as_table_filter_sub_tables_layout.html', context) return mark_safe(html) else: if isinstance(data, collections.Iterable): for row in data: row_dict = Obj.get_dict(row, filter_list, exclude_list, verbose_key=True, get_display=True) for k, v in row_dict.items(): if isinstance(v, list): if v: row_dict[k] = as_table(v, filter_param) result.append(row_dict) else: result.append(Obj.get_dict(data, verbose_key=True)) if result: headers = [] if model is not None: columns = result[0].keys() headers = list(Mdl.get_field_verbose(model, columns).values()) else: for k, v in result[0].items(): if Str.is_int(k): headers.append(type(v).__name__) elif type(k) is str and k.islower(): headers.append(Str.snake_to_title(k)) else: headers.append(k) context = {'headers': headers, 'data': result} html = render_to_string('lazifier/table_filter/as_table_filter_layout.html', context) else: return None return mark_safe(html)