def _resolve_filter(self, queryset: "AwaitableStatement[MODEL]", context: QueryContext, key, value) -> QueryClauses: context_item = context.top model = context_item.model table = context_item.table if value is None and "isnull" in model._meta.db.filter_class.FILTER_FUNC_MAP: value = True key = f"{key}{LOOKUP_SEP}isnull" relation_field_name, _, field_sub = key.partition(LOOKUP_SEP) if self._check_annotations and relation_field_name in queryset.annotations: (filter_operator, _) = model._meta.db.filter_class.FILTER_FUNC_MAP[field_sub] annotation = queryset.annotations[relation_field_name] if annotation.field.is_aggregate: return QueryClauses(having_criterion=filter_operator(annotation.field, value)) else: return QueryClauses(where_criterion=filter_operator(annotation.field, value)) field_object = model._meta.fields_map.get(relation_field_name) if not field_object: raise UnknownFieldError(relation_field_name, model) key_filter = model._meta.get_filter(key) if key_filter: if isinstance(field_object, RelationField): join_data = context.join_table_by_field(table, field_object, full=False) if join_data: # # We are potentially adding two None here into the context # however, since we have a valid key_filter it means no sub_field # and hence to inner tables and no context is necessary, except # for the correct position of the stack levels, # context.push(join_data.model, join_data.table) clauses = QueryClauses(where_criterion=key_filter(context, value)) context.pop() else: clauses = QueryClauses(where_criterion=key_filter(context, value)) return clauses else: return QueryClauses(where_criterion=key_filter(context, value)) if isinstance(field_object, RelationField): join_data = context.join_table_by_field(table, field_object) context.push(join_data.model, join_data.table) q = Q(**{field_sub: value}) q._check_annotations = False modifier = q._resolve(queryset=queryset, context=context) context.pop() return modifier raise BaseFieldError(key, model)
def resolve_into(self, queryset: "AwaitableStatement[MODEL]", context: QueryContext): self._field_object, self._field = context.resolve_term( self._term, queryset, accept_relation=True) model = context.top.model table = context.top.table if self._add_group_by and self._field.is_aggregate: context.query = context.query.groupby( table[model._meta.pk_db_column])
def resolve_into(self, queryset: "AwaitableQuery[MODEL]", context: QueryContext): # So far as I can imagine, the annotation will be expanded # independently, we just refer to it here. _, field = context.resolve_field_name(self.field_name, queryset, accept_relation=False, expand_annotation=False) if not queryset.is_aggregate() or context.query._groupbys: context.query = context.query.orderby(field, order=self.direction)
def resolve_into(self, queryset: "AwaitableQuery[MODEL]", context: QueryContext): if isinstance(self.node, Term): term_annotation = TermAnnotation(self.node) term_annotation.resolve_into(queryset, context) field = term_annotation.field direction = Order.asc if isinstance(field, Negative): field = field.term direction = Order.desc context.query = context.query.orderby(field, order=direction) else: context.query = context.query.orderby(self.node)
def test_q_with_blank_or3(self): q = Q() | Q(id__gt=5) r = q._resolve( TestQCall.DummyQuerySet(), QueryContext(QueryBuilder()).push(CharFields, CharFields._meta.table()) ) self.assertEqual(r.where_criterion.get_sql(), '"id">5')
def test_q_complex_int3(self): q = Q(Q(id__lt=5, id__gt=50, join_type="OR"), join_type="AND", intnum=80) r = q._resolve( TestQCall.DummyQuerySet(), QueryContext(QueryBuilder()).push(IntFields, IntFields._meta.table()) ) self.assertEqual(r.where_criterion.get_sql(), '"intnum"=80 AND ("id"<5 OR "id">50)')
def test_q_multiple_or2(self): q = Q(join_type="OR", id=8, intnum=80) r = q._resolve( TestQCall.DummyQuerySet(), QueryContext(QueryBuilder()).push(IntFields, IntFields._meta.table()) ) self.assertEqual(r.where_criterion.get_sql(), '"id"=8 OR "intnum"=80')
def test_q_multiple_and(self): q = Q(join_type="AND", id__gt=8, id__lt=10) r = q._resolve( TestQCall.DummyQuerySet(), QueryContext(QueryBuilder()).push(IntFields, IntFields._meta.table()) ) self.assertEqual(r.where_criterion.get_sql(), '"id">8 AND "id"<10')
def test_q_basic_or(self): q = Q(join_type="OR", id=8) r = q._resolve( TestQCall.DummyQuerySet(), QueryContext(QueryBuilder()).push(IntFields, IntFields._meta.table()) ) self.assertEqual(r.where_criterion.get_sql(), '"id"=8')
def create_query_context(self, parent_context: Optional[QueryContext]) -> QueryContext: query = self.query_builder(parent_context.alias if parent_context else None)\ .select(*self.model._meta.db_columns) context = QueryContext(query, parent_context) context.push(self.model, query._from[-1]) context.resolve_select_related(self._select_related) context.pop() return context
def test_q_complex_char3(self): q = Q(~Q(char__lt=5, char__gt=50, join_type="OR"), join_type="AND", char_null=80) r = q._resolve( TestQCall.DummyQuerySet(), QueryContext(QueryBuilder()).push(CharFields, CharFields._meta.table()) ) self.assertEqual( r.where_criterion.get_sql(), "\"char_null\"='80' AND NOT (\"char\"<'5' OR \"char\">'50')", )
def create_query(self, parent_context: Optional[QueryContext]) -> QueryBuilder: query = self.query_builder(parent_context.alias if parent_context else None) context = QueryContext(query, parent_context) context.push(self.model, query._from[-1]) self._add_query_details(context=context) context.query._delete_from = True context.pop() return context.query
def create_query(self, parent_context: Optional[QueryContext]) -> QueryBuilder: db_client = self._get_db_client() table = self.model._meta.table(parent_context.alias if parent_context else None) context = QueryContext(query=db_client.query_class.update(table), parent_context=parent_context) context.push(self.model, table) self._add_query_details(context=context) for field_name, value in self.update_kwargs.items(): field_object = self.model._meta.fields_map.get(field_name) if not field_object: raise UnknownFieldError(field_name, self.model) if field_object.primary_key: raise IntegrityError(f"Field {field_name} is primary key and can not be updated") if isinstance(field_object, RelationField): if isinstance(field_object, (ForeignKey, OneToOneField)): fk_field_name: str = field_object.id_field_name fk_field_object = self.model._meta.fields_map[fk_field_name] value = fk_field_object.db_value(value.pk, None) context.query = context.query.set(fk_field_object.db_column, value) else: raise NotADbColumnFieldError(field_name, self.model) else: if isinstance(value, Term): value = TermAnnotation(value) value.resolve_into(self, context) value = value.field elif isinstance(value, Annotation): value.resolve_into(self, context) value = value.field else: value = field_object.db_value(value, None) context.query = context.query.set(field_object.db_column, value) context.pop() return context.query
def create_query(self, parent_context: QueryContext) -> QueryBuilder: query = self.query_builder( parent_context.alias if parent_context else None) context = QueryContext(query, parent_context) context.push(self.model, query._from[-1]) self._add_query_details(context=context) for return_as, field_name in self.fields_for_select.items(): _, field = context.resolve_field_name(field_name, self, accept_relation=False) context.query._select_other(field.as_(return_as)) context.pop() return context.query