def select_related(self, *args): select_related = {"action": "_db__select_related", "fields": []} for arg in args: # fr the time been we overlook the after the '__' if "__" in arg: arg = arg.split("__")[0] if not hasattr(self.model, arg): raise AsyncOrmQuerysetError("{} is not a {} attribute.".format( arg, self.model.__name__)) if not isinstance(getattr(self.model, arg), ForeignKey): raise AsyncOrmQuerysetError( "{} is not a ForeignKey Field for {}.".format( arg, self.model.__name__)) model = self.orm.get_model(getattr(self.model, arg).foreign_key) right_table = model.table_name or model.__name__.lower() left_table = self.model.table_name or self.model.__name__.lower() fields_formatter = ", ".join([ "{right_table}.{field} AS {right_table}€$$€{field}".format( right_table=right_table, field=field) for field in model.get_db_columns() ]) select_related["fields"].append({ "right_table": right_table, "left_table": left_table, "foreign_field": arg, "model_db_pk": model.db_pk, "fields_formatter": fields_formatter, "orm_fieldname": arg, }) queryset = self._copy_me() queryset.query.append(select_related) return queryset
async def calculate(self, field_name, operation): if hasattr(self.model, field_name): field = getattr(self.model, field_name) else: raise AsyncOrmQuerysetError( "{} wrong field name for model {}".format( field_name, self.model.__name__)) if not isinstance(field, NumberField): raise AsyncOrmQuerysetError( "{} is not a numeric field".format(field_name)) query = self.query_copy() query[0]["select"] = "{}({})".format(operation, field_name) resp = await self.db_request(query) for v in resp.values(): return v
async def __getitem__(self, key): if isinstance(key, slice): wrong_start_key = key.start is not None and key.start < 0 wrong_stop_key = key.stop is not None and key.stop < 0 if wrong_start_key or wrong_stop_key: raise AsyncOrmQuerysetError("Negative indices are not allowed") if key.step is not None: raise AsyncOrmQuerysetError("Step on Queryset is not allowed") return self._get_queryset_slice(key) elif isinstance(key, int): if key < 0: raise AsyncOrmQuerysetError("Negative indices are not allowed") return await self._get_item(key) else: raise TypeError("Invalid argument type.")
def only(self, *args): # retrieves from the database only the attrs requested # all the rest come as None for arg in args: if not hasattr(self.model, arg): raise AsyncOrmQuerysetError( "{} is not a correct field for {}".format( arg, self.model.__name__)) queryset = self.queryset() queryset.query = self.query_copy() queryset.query[0]["select"] = ",".join(args) return queryset
def order_by(self, *args): # retrieves from the database only the attrs requested # all the rest come as None final_args = [] for arg in args: if arg[0] == "-": arg = arg[1:] final_args.append("-" + arg) else: final_args.append(arg) if not hasattr(self.model, arg): raise AsyncOrmQuerysetError( "{} is not a correct field for {}".format( arg, self.model.__name__)) queryset = self.queryset() queryset.query = self.query_copy() queryset.query[0]["ordering"] = final_args return queryset
def calc_filters(self, kwargs, exclude): # recompose the filters bool_string = exclude and "NOT " or "" filters = [] for k, v in kwargs.items(): # we format the key, the conditional and the value operator = "{t_n}.{k} = {v}" lookup = None if len(k.split("__")) > 1: k, lookup = k.split("__") operator = LOOKUP_OPERATOR[lookup] field = getattr(self.model, k) string_lookups = [ "exact", "iexact", "contains", "icontains", "startswith", "istartswith", "endswith", "iendswith", ] operator_formater = { "t_n": self.model.table_name or self.model.__name__.lower(), "k": field.db_column, "v": v, } if operator == "({t_n}.{k}>={min} AND {t_n}.{k}<={max})": if not isinstance(v, (tuple, list)): raise AsyncOrmQuerysetError( "{} should be list or a tuple".format(lookup)) if len(v) != 2: raise AsyncOrmQuerysetError( "Not a correct tuple/list definition, should be of size 2" ) operator_formater.update({ "min": field.sanitize_data(v[0]), "max": field.sanitize_data(v[1]) }) elif lookup in string_lookups: is_charfield = isinstance(field, CharField) # is_othercharfield = issubclass(field, CharField) # if not is_charfield or not is_othercharfield: if not is_charfield: raise AsyncOrmQuerysetError( "{} not allowed in non CharField fields".format( lookup)) operator_formater["v"] = field.sanitize_data(v) elif lookup == "in" and isinstance(v, (list, tuple)) and not v: # we can skip this case to avoid error with empty array raise AsyncOrmEmptyResult else: if isinstance(v, (list, tuple)): # check they are correct items and serialize v = ",".join([ "'{}'".format(field.sanitize_data(si)) if isinstance( si, str) else str(si) for si in v ]) elif v is None: v = field.sanitize_data(v)[1:-1] operator = operator.replace("=", "IS") elif isinstance( v, (datetime.datetime, datetime.date)) or isinstance( field, (CharField)): v = "'{}'".format(v) else: v = field.sanitize_data(v) operator_formater["v"] = v filters.append(bool_string + operator.format(**operator_formater)) return filters