From 5d91dc8ee3ff7e2230cfacf41005f61b8efbf057 Mon Sep 17 00:00:00 2001 From: Gagaro Date: Mon, 31 Jan 2022 16:04:13 +0100 Subject: Refs #30581 -- Added Q.check() hook. --- django/db/models/query_utils.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'django') diff --git a/django/db/models/query_utils.py b/django/db/models/query_utils.py index 746efce67f..9b5824f89f 100644 --- a/django/db/models/query_utils.py +++ b/django/db/models/query_utils.py @@ -8,12 +8,16 @@ circular import difficulties. import copy import functools import inspect +import logging from collections import namedtuple from django.core.exceptions import FieldError +from django.db import DEFAULT_DB_ALIAS, DatabaseError from django.db.models.constants import LOOKUP_SEP from django.utils import tree +logger = logging.getLogger("django.db.models") + # PathInfo is used when converting lookups (fk__somecol). The contents # describe the relation in Model terms (model Options and Fields for both # sides of the relation. The join_field is the field backing the relation. @@ -110,6 +114,31 @@ class Q(tree.Node): else: yield child + def check(self, against, using=DEFAULT_DB_ALIAS): + """ + Do a database query to check if the expressions of the Q instance + matches against the expressions. + """ + # Avoid circular imports. + from django.db.models import Value + from django.db.models.sql import Query + from django.db.models.sql.constants import SINGLE + + query = Query(None) + for name, value in against.items(): + if not hasattr(value, "resolve_expression"): + value = Value(value) + query.add_annotation(value, name, select=False) + query.add_annotation(Value(1), "_check") + # This will raise a FieldError if a field is missing in "against". + query.add_q(self) + compiler = query.get_compiler(using=using) + try: + return compiler.execute_sql(SINGLE) is not None + except DatabaseError as e: + logger.warning("Got a database error calling check() on %r: %s", self, e) + return True + def deconstruct(self): path = "%s.%s" % (self.__class__.__module__, self.__class__.__name__) if path.startswith("django.db.models.query_utils"): -- cgit v1.3