Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Refactored get_query_set_class() to DatabaseOperations.query_set_clas…

…s(). Also added BaseDatabaseFeatures.uses_custom_queryset. Refs #5106

git-svn-id: http://code.djangoproject.com/svn/django/trunk@5976 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit e13ea3c70dc1a217d4e88e0a66f4311167f156c3 1 parent 6d8e609
Adrian Holovaty authored August 20, 2007
10  django/db/backends/__init__.py
@@ -48,6 +48,7 @@ class BaseDatabaseFeatures(object):
48 48
     supports_constraints = True
49 49
     supports_tablespaces = False
50 50
     uses_case_insensitive_names = False
  51
+    uses_custom_queryset = False
51 52
 
52 53
 class BaseDatabaseOperations(object):
53 54
     """
@@ -144,6 +145,15 @@ def pk_default_value(self):
144 145
         """
145 146
         return 'DEFAULT'
146 147
 
  148
+    def query_set_class(self, DefaultQuerySet):
  149
+        """
  150
+        Given the default QuerySet class, returns a custom QuerySet class
  151
+        to use for this backend. Returns None if a custom QuerySet isn't used.
  152
+        See also BaseDatabaseFeatures.uses_custom_queryset, which regulates
  153
+        whether this method is called at all.
  154
+        """
  155
+        return None
  156
+
147 157
     def quote_name(self, name):
148 158
         """
149 159
         Returns a quoted version of the given table, index or column name. Does
478  django/db/backends/oracle/base.py
@@ -28,6 +28,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
28 28
     needs_upper_for_iops = True
29 29
     supports_tablespaces = True
30 30
     uses_case_insensitive_names = True
  31
+    uses_custom_queryset = True
31 32
 
32 33
 class DatabaseOperations(BaseDatabaseOperations):
33 34
     def autoinc_sql(self, table):
@@ -78,6 +79,243 @@ def limit_offset_sql(self, limit, offset=None):
78 79
     def max_name_length(self):
79 80
         return 30
80 81
 
  82
+    def query_set_class(self, DefaultQuerySet):
  83
+        from django.db import connection
  84
+        from django.db.models.query import EmptyResultSet, GET_ITERATOR_CHUNK_SIZE, quote_only_if_word
  85
+
  86
+        class OracleQuerySet(DefaultQuerySet):
  87
+
  88
+            def iterator(self):
  89
+                "Performs the SELECT database lookup of this QuerySet."
  90
+
  91
+                from django.db.models.query import get_cached_row
  92
+
  93
+                # self._select is a dictionary, and dictionaries' key order is
  94
+                # undefined, so we convert it to a list of tuples.
  95
+                extra_select = self._select.items()
  96
+
  97
+                full_query = None
  98
+
  99
+                try:
  100
+                    try:
  101
+                        select, sql, params, full_query = self._get_sql_clause(get_full_query=True)
  102
+                    except TypeError:
  103
+                        select, sql, params = self._get_sql_clause()
  104
+                except EmptyResultSet:
  105
+                    raise StopIteration
  106
+                if not full_query:
  107
+                    full_query = "SELECT %s%s\n%s" % \
  108
+                                 ((self._distinct and "DISTINCT " or ""),
  109
+                                  ', '.join(select), sql)
  110
+
  111
+                cursor = connection.cursor()
  112
+                cursor.execute(full_query, params)
  113
+
  114
+                fill_cache = self._select_related
  115
+                fields = self.model._meta.fields
  116
+                index_end = len(fields)
  117
+
  118
+                # so here's the logic;
  119
+                # 1. retrieve each row in turn
  120
+                # 2. convert NCLOBs
  121
+
  122
+                while 1:
  123
+                    rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE)
  124
+                    if not rows:
  125
+                        raise StopIteration
  126
+                    for row in rows:
  127
+                        row = self.resolve_columns(row, fields)
  128
+                        if fill_cache:
  129
+                            obj, index_end = get_cached_row(klass=self.model, row=row,
  130
+                                                            index_start=0, max_depth=self._max_related_depth)
  131
+                        else:
  132
+                            obj = self.model(*row[:index_end])
  133
+                        for i, k in enumerate(extra_select):
  134
+                            setattr(obj, k[0], row[index_end+i])
  135
+                        yield obj
  136
+
  137
+
  138
+            def _get_sql_clause(self, get_full_query=False):
  139
+                from django.db.models.query import fill_table_cache, \
  140
+                    handle_legacy_orderlist, orderfield2column
  141
+
  142
+                opts = self.model._meta
  143
+                qn = connection.ops.quote_name
  144
+
  145
+                # Construct the fundamental parts of the query: SELECT X FROM Y WHERE Z.
  146
+                select = ["%s.%s" % (qn(opts.db_table), qn(f.column)) for f in opts.fields]
  147
+                tables = [quote_only_if_word(t) for t in self._tables]
  148
+                joins = SortedDict()
  149
+                where = self._where[:]
  150
+                params = self._params[:]
  151
+
  152
+                # Convert self._filters into SQL.
  153
+                joins2, where2, params2 = self._filters.get_sql(opts)
  154
+                joins.update(joins2)
  155
+                where.extend(where2)
  156
+                params.extend(params2)
  157
+
  158
+                # Add additional tables and WHERE clauses based on select_related.
  159
+                if self._select_related:
  160
+                    fill_table_cache(opts, select, tables, where, opts.db_table, [opts.db_table])
  161
+
  162
+                # Add any additional SELECTs.
  163
+                if self._select:
  164
+                    select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), qn(s[0])) for s in self._select.items()])
  165
+
  166
+                # Start composing the body of the SQL statement.
  167
+                sql = [" FROM", qn(opts.db_table)]
  168
+
  169
+                # Compose the join dictionary into SQL describing the joins.
  170
+                if joins:
  171
+                    sql.append(" ".join(["%s %s %s ON %s" % (join_type, table, alias, condition)
  172
+                                    for (alias, (table, join_type, condition)) in joins.items()]))
  173
+
  174
+                # Compose the tables clause into SQL.
  175
+                if tables:
  176
+                    sql.append(", " + ", ".join(tables))
  177
+
  178
+                # Compose the where clause into SQL.
  179
+                if where:
  180
+                    sql.append(where and "WHERE " + " AND ".join(where))
  181
+
  182
+                # ORDER BY clause
  183
+                order_by = []
  184
+                if self._order_by is not None:
  185
+                    ordering_to_use = self._order_by
  186
+                else:
  187
+                    ordering_to_use = opts.ordering
  188
+                for f in handle_legacy_orderlist(ordering_to_use):
  189
+                    if f == '?': # Special case.
  190
+                        order_by.append(DatabaseOperations().random_function_sql())
  191
+                    else:
  192
+                        if f.startswith('-'):
  193
+                            col_name = f[1:]
  194
+                            order = "DESC"
  195
+                        else:
  196
+                            col_name = f
  197
+                            order = "ASC"
  198
+                        if "." in col_name:
  199
+                            table_prefix, col_name = col_name.split('.', 1)
  200
+                            table_prefix = qn(table_prefix) + '.'
  201
+                        else:
  202
+                            # Use the database table as a column prefix if it wasn't given,
  203
+                            # and if the requested column isn't a custom SELECT.
  204
+                            if "." not in col_name and col_name not in (self._select or ()):
  205
+                                table_prefix = qn(opts.db_table) + '.'
  206
+                            else:
  207
+                                table_prefix = ''
  208
+                        order_by.append('%s%s %s' % (table_prefix, qn(orderfield2column(col_name, opts)), order))
  209
+                if order_by:
  210
+                    sql.append("ORDER BY " + ", ".join(order_by))
  211
+
  212
+                # Look for column name collisions in the select elements
  213
+                # and fix them with an AS alias.  This allows us to do a
  214
+                # SELECT * later in the paging query.
  215
+                cols = [clause.split('.')[-1] for clause in select]
  216
+                for index, col in enumerate(cols):
  217
+                    if cols.count(col) > 1:
  218
+                        col = '%s%d' % (col.replace('"', ''), index)
  219
+                        cols[index] = col
  220
+                        select[index] = '%s AS %s' % (select[index], col)
  221
+
  222
+                # LIMIT and OFFSET clauses
  223
+                # To support limits and offsets, Oracle requires some funky rewriting of an otherwise normal looking query.
  224
+                select_clause = ",".join(select)
  225
+                distinct = (self._distinct and "DISTINCT " or "")
  226
+
  227
+                if order_by:
  228
+                    order_by_clause = " OVER (ORDER BY %s )" % (", ".join(order_by))
  229
+                else:
  230
+                    #Oracle's row_number() function always requires an order-by clause.
  231
+                    #So we need to define a default order-by, since none was provided.
  232
+                    order_by_clause = " OVER (ORDER BY %s.%s)" % \
  233
+                        (qn(opts.db_table), qn(opts.fields[0].db_column or opts.fields[0].column))
  234
+                # limit_and_offset_clause
  235
+                if self._limit is None:
  236
+                    assert self._offset is None, "'offset' is not allowed without 'limit'"
  237
+
  238
+                if self._offset is not None:
  239
+                    offset = int(self._offset)
  240
+                else:
  241
+                    offset = 0
  242
+                if self._limit is not None:
  243
+                    limit = int(self._limit)
  244
+                else:
  245
+                    limit = None
  246
+
  247
+                limit_and_offset_clause = ''
  248
+                if limit is not None:
  249
+                    limit_and_offset_clause = "WHERE rn > %s AND rn <= %s" % (offset, limit+offset)
  250
+                elif offset:
  251
+                    limit_and_offset_clause = "WHERE rn > %s" % (offset)
  252
+
  253
+                if len(limit_and_offset_clause) > 0:
  254
+                    fmt = \
  255
+    """SELECT * FROM
  256
+      (SELECT %s%s,
  257
+              ROW_NUMBER()%s AS rn
  258
+       %s)
  259
+    %s"""
  260
+                    full_query = fmt % (distinct, select_clause,
  261
+                                        order_by_clause, ' '.join(sql).strip(),
  262
+                                        limit_and_offset_clause)
  263
+                else:
  264
+                    full_query = None
  265
+
  266
+                if get_full_query:
  267
+                    return select, " ".join(sql), params, full_query
  268
+                else:
  269
+                    return select, " ".join(sql), params
  270
+
  271
+            def resolve_columns(self, row, fields=()):
  272
+                from django.db.models.fields import DateField, DateTimeField, \
  273
+                    TimeField, BooleanField, NullBooleanField, DecimalField, Field
  274
+                values = []
  275
+                for value, field in map(None, row, fields):
  276
+                    if isinstance(value, Database.LOB):
  277
+                        value = value.read()
  278
+                    # Oracle stores empty strings as null. We need to undo this in
  279
+                    # order to adhere to the Django convention of using the empty
  280
+                    # string instead of null, but only if the field accepts the
  281
+                    # empty string.
  282
+                    if value is None and isinstance(field, Field) and field.empty_strings_allowed:
  283
+                        value = ''
  284
+                    # Convert 1 or 0 to True or False
  285
+                    elif value in (1, 0) and isinstance(field, (BooleanField, NullBooleanField)):
  286
+                        value = bool(value)
  287
+                    # Convert floats to decimals
  288
+                    elif value is not None and isinstance(field, DecimalField):
  289
+                        value = util.typecast_decimal(field.format_number(value))
  290
+                    # cx_Oracle always returns datetime.datetime objects for
  291
+                    # DATE and TIMESTAMP columns, but Django wants to see a
  292
+                    # python datetime.date, .time, or .datetime.  We use the type
  293
+                    # of the Field to determine which to cast to, but it's not
  294
+                    # always available.
  295
+                    # As a workaround, we cast to date if all the time-related
  296
+                    # values are 0, or to time if the date is 1/1/1900.
  297
+                    # This could be cleaned a bit by adding a method to the Field
  298
+                    # classes to normalize values from the database (the to_python
  299
+                    # method is used for validation and isn't what we want here).
  300
+                    elif isinstance(value, Database.Timestamp):
  301
+                        # In Python 2.3, the cx_Oracle driver returns its own
  302
+                        # Timestamp object that we must convert to a datetime class.
  303
+                        if not isinstance(value, datetime.datetime):
  304
+                            value = datetime.datetime(value.year, value.month, value.day, value.hour,
  305
+                                                      value.minute, value.second, value.fsecond)
  306
+                        if isinstance(field, DateTimeField):
  307
+                            pass  # DateTimeField subclasses DateField so must be checked first.
  308
+                        elif isinstance(field, DateField):
  309
+                            value = value.date()
  310
+                        elif isinstance(field, TimeField) or (value.year == 1900 and value.month == value.day == 1):
  311
+                            value = value.time()
  312
+                        elif value.hour == value.minute == value.second == value.microsecond == 0:
  313
+                            value = value.date()
  314
+                    values.append(value)
  315
+                return values
  316
+
  317
+        return OracleQuerySet
  318
+
81 319
     def quote_name(self, name):
82 320
         # SQL92 requires delimited (quoted) names to be case-sensitive.  When
83 321
         # not quoted, Oracle has case-insensitive behavior for identifiers, but
@@ -261,246 +499,6 @@ def get_trigger_name(table):
261 499
     name_length = DatabaseOperations().max_name_length() - 3
262 500
     return '%s_TR' % util.truncate_name(table, name_length).upper()
263 501
 
264  
-def get_query_set_class(DefaultQuerySet):
265  
-    "Create a custom QuerySet class for Oracle."
266  
-
267  
-    from django.db import connection
268  
-    from django.db.models.query import EmptyResultSet, GET_ITERATOR_CHUNK_SIZE, quote_only_if_word
269  
-
270  
-    class OracleQuerySet(DefaultQuerySet):
271  
-
272  
-        def iterator(self):
273  
-            "Performs the SELECT database lookup of this QuerySet."
274  
-
275  
-            from django.db.models.query import get_cached_row
276  
-
277  
-            # self._select is a dictionary, and dictionaries' key order is
278  
-            # undefined, so we convert it to a list of tuples.
279  
-            extra_select = self._select.items()
280  
-
281  
-            full_query = None
282  
-
283  
-            try:
284  
-                try:
285  
-                    select, sql, params, full_query = self._get_sql_clause(get_full_query=True)
286  
-                except TypeError:
287  
-                    select, sql, params = self._get_sql_clause()
288  
-            except EmptyResultSet:
289  
-                raise StopIteration
290  
-            if not full_query:
291  
-                full_query = "SELECT %s%s\n%s" % \
292  
-                             ((self._distinct and "DISTINCT " or ""),
293  
-                              ', '.join(select), sql)
294  
-
295  
-            cursor = connection.cursor()
296  
-            cursor.execute(full_query, params)
297  
-
298  
-            fill_cache = self._select_related
299  
-            fields = self.model._meta.fields
300  
-            index_end = len(fields)
301  
-
302  
-            # so here's the logic;
303  
-            # 1. retrieve each row in turn
304  
-            # 2. convert NCLOBs
305  
-
306  
-            while 1:
307  
-                rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE)
308  
-                if not rows:
309  
-                    raise StopIteration
310  
-                for row in rows:
311  
-                    row = self.resolve_columns(row, fields)
312  
-                    if fill_cache:
313  
-                        obj, index_end = get_cached_row(klass=self.model, row=row,
314  
-                                                        index_start=0, max_depth=self._max_related_depth)
315  
-                    else:
316  
-                        obj = self.model(*row[:index_end])
317  
-                    for i, k in enumerate(extra_select):
318  
-                        setattr(obj, k[0], row[index_end+i])
319  
-                    yield obj
320  
-
321  
-
322  
-        def _get_sql_clause(self, get_full_query=False):
323  
-            from django.db.models.query import fill_table_cache, \
324  
-                handle_legacy_orderlist, orderfield2column
325  
-
326  
-            opts = self.model._meta
327  
-            qn = connection.ops.quote_name
328  
-
329  
-            # Construct the fundamental parts of the query: SELECT X FROM Y WHERE Z.
330  
-            select = ["%s.%s" % (qn(opts.db_table), qn(f.column)) for f in opts.fields]
331  
-            tables = [quote_only_if_word(t) for t in self._tables]
332  
-            joins = SortedDict()
333  
-            where = self._where[:]
334  
-            params = self._params[:]
335  
-
336  
-            # Convert self._filters into SQL.
337  
-            joins2, where2, params2 = self._filters.get_sql(opts)
338  
-            joins.update(joins2)
339  
-            where.extend(where2)
340  
-            params.extend(params2)
341  
-
342  
-            # Add additional tables and WHERE clauses based on select_related.
343  
-            if self._select_related:
344  
-                fill_table_cache(opts, select, tables, where, opts.db_table, [opts.db_table])
345  
-
346  
-            # Add any additional SELECTs.
347  
-            if self._select:
348  
-                select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), qn(s[0])) for s in self._select.items()])
349  
-
350  
-            # Start composing the body of the SQL statement.
351  
-            sql = [" FROM", qn(opts.db_table)]
352  
-
353  
-            # Compose the join dictionary into SQL describing the joins.
354  
-            if joins:
355  
-                sql.append(" ".join(["%s %s %s ON %s" % (join_type, table, alias, condition)
356  
-                                for (alias, (table, join_type, condition)) in joins.items()]))
357  
-
358  
-            # Compose the tables clause into SQL.
359  
-            if tables:
360  
-                sql.append(", " + ", ".join(tables))
361  
-
362  
-            # Compose the where clause into SQL.
363  
-            if where:
364  
-                sql.append(where and "WHERE " + " AND ".join(where))
365  
-
366  
-            # ORDER BY clause
367  
-            order_by = []
368  
-            if self._order_by is not None:
369  
-                ordering_to_use = self._order_by
370  
-            else:
371  
-                ordering_to_use = opts.ordering
372  
-            for f in handle_legacy_orderlist(ordering_to_use):
373  
-                if f == '?': # Special case.
374  
-                    order_by.append(DatabaseOperations().random_function_sql())
375  
-                else:
376  
-                    if f.startswith('-'):
377  
-                        col_name = f[1:]
378  
-                        order = "DESC"
379  
-                    else:
380  
-                        col_name = f
381  
-                        order = "ASC"
382  
-                    if "." in col_name:
383  
-                        table_prefix, col_name = col_name.split('.', 1)
384  
-                        table_prefix = qn(table_prefix) + '.'
385  
-                    else:
386  
-                        # Use the database table as a column prefix if it wasn't given,
387  
-                        # and if the requested column isn't a custom SELECT.
388  
-                        if "." not in col_name and col_name not in (self._select or ()):
389  
-                            table_prefix = qn(opts.db_table) + '.'
390  
-                        else:
391  
-                            table_prefix = ''
392  
-                    order_by.append('%s%s %s' % (table_prefix, qn(orderfield2column(col_name, opts)), order))
393  
-            if order_by:
394  
-                sql.append("ORDER BY " + ", ".join(order_by))
395  
-
396  
-            # Look for column name collisions in the select elements
397  
-            # and fix them with an AS alias.  This allows us to do a
398  
-            # SELECT * later in the paging query.
399  
-            cols = [clause.split('.')[-1] for clause in select]
400  
-            for index, col in enumerate(cols):
401  
-                if cols.count(col) > 1:
402  
-                    col = '%s%d' % (col.replace('"', ''), index)
403  
-                    cols[index] = col
404  
-                    select[index] = '%s AS %s' % (select[index], col)
405  
-
406  
-            # LIMIT and OFFSET clauses
407  
-            # To support limits and offsets, Oracle requires some funky rewriting of an otherwise normal looking query.
408  
-            select_clause = ",".join(select)
409  
-            distinct = (self._distinct and "DISTINCT " or "")
410  
-
411  
-            if order_by:
412  
-                order_by_clause = " OVER (ORDER BY %s )" % (", ".join(order_by))
413  
-            else:
414  
-                #Oracle's row_number() function always requires an order-by clause.
415  
-                #So we need to define a default order-by, since none was provided.
416  
-                order_by_clause = " OVER (ORDER BY %s.%s)" % \
417  
-                    (qn(opts.db_table), qn(opts.fields[0].db_column or opts.fields[0].column))
418  
-            # limit_and_offset_clause
419  
-            if self._limit is None:
420  
-                assert self._offset is None, "'offset' is not allowed without 'limit'"
421  
-
422  
-            if self._offset is not None:
423  
-                offset = int(self._offset)
424  
-            else:
425  
-                offset = 0
426  
-            if self._limit is not None:
427  
-                limit = int(self._limit)
428  
-            else:
429  
-                limit = None
430  
-
431  
-            limit_and_offset_clause = ''
432  
-            if limit is not None:
433  
-                limit_and_offset_clause = "WHERE rn > %s AND rn <= %s" % (offset, limit+offset)
434  
-            elif offset:
435  
-                limit_and_offset_clause = "WHERE rn > %s" % (offset)
436  
-
437  
-            if len(limit_and_offset_clause) > 0:
438  
-                fmt = \
439  
-"""SELECT * FROM
440  
-  (SELECT %s%s,
441  
-          ROW_NUMBER()%s AS rn
442  
-   %s)
443  
-%s"""
444  
-                full_query = fmt % (distinct, select_clause,
445  
-                                    order_by_clause, ' '.join(sql).strip(),
446  
-                                    limit_and_offset_clause)
447  
-            else:
448  
-                full_query = None
449  
-
450  
-            if get_full_query:
451  
-                return select, " ".join(sql), params, full_query
452  
-            else:
453  
-                return select, " ".join(sql), params
454  
-
455  
-        def resolve_columns(self, row, fields=()):
456  
-            from django.db.models.fields import DateField, DateTimeField, \
457  
-                TimeField, BooleanField, NullBooleanField, DecimalField, Field
458  
-            values = []
459  
-            for value, field in map(None, row, fields):
460  
-                if isinstance(value, Database.LOB):
461  
-                    value = value.read()
462  
-                # Oracle stores empty strings as null. We need to undo this in
463  
-                # order to adhere to the Django convention of using the empty
464  
-                # string instead of null, but only if the field accepts the
465  
-                # empty string.
466  
-                if value is None and isinstance(field, Field) and field.empty_strings_allowed:
467  
-                    value = ''
468  
-                # Convert 1 or 0 to True or False
469  
-                elif value in (1, 0) and isinstance(field, (BooleanField, NullBooleanField)):
470  
-                    value = bool(value)
471  
-                # Convert floats to decimals
472  
-                elif value is not None and isinstance(field, DecimalField):
473  
-                    value = util.typecast_decimal(field.format_number(value))
474  
-                # cx_Oracle always returns datetime.datetime objects for
475  
-                # DATE and TIMESTAMP columns, but Django wants to see a
476  
-                # python datetime.date, .time, or .datetime.  We use the type
477  
-                # of the Field to determine which to cast to, but it's not
478  
-                # always available.
479  
-                # As a workaround, we cast to date if all the time-related
480  
-                # values are 0, or to time if the date is 1/1/1900.
481  
-                # This could be cleaned a bit by adding a method to the Field
482  
-                # classes to normalize values from the database (the to_python
483  
-                # method is used for validation and isn't what we want here).
484  
-                elif isinstance(value, Database.Timestamp):
485  
-                    # In Python 2.3, the cx_Oracle driver returns its own
486  
-                    # Timestamp object that we must convert to a datetime class.
487  
-                    if not isinstance(value, datetime.datetime):
488  
-                        value = datetime.datetime(value.year, value.month, value.day, value.hour,
489  
-                                                  value.minute, value.second, value.fsecond)
490  
-                    if isinstance(field, DateTimeField):
491  
-                        pass  # DateTimeField subclasses DateField so must be checked first.
492  
-                    elif isinstance(field, DateField):
493  
-                        value = value.date()
494  
-                    elif isinstance(field, TimeField) or (value.year == 1900 and value.month == value.day == 1):
495  
-                        value = value.time()
496  
-                    elif value.hour == value.minute == value.second == value.microsecond == 0:
497  
-                        value = value.date()
498  
-                values.append(value)
499  
-            return values
500  
-
501  
-    return OracleQuerySet
502  
-
503  
-
504 502
 OPERATOR_MAPPING = {
505 503
     'exact': '= %s',
506 504
     'iexact': '= UPPER(%s)',
6  django/db/models/query.py
@@ -564,9 +564,9 @@ def _get_sql_clause(self):
564 564
 
565 565
         return select, " ".join(sql), params
566 566
 
567  
-# Use the backend's QuerySet class if it defines one, otherwise use _QuerySet.
568  
-if hasattr(backend, 'get_query_set_class'):
569  
-    QuerySet = backend.get_query_set_class(_QuerySet)
  567
+# Use the backend's QuerySet class if it defines one. Otherwise, use _QuerySet.
  568
+if connection.features.uses_custom_queryset:
  569
+    QuerySet = connection.ops.query_set_class(_QuerySet)
570 570
 else:
571 571
     QuerySet = _QuerySet
572 572
 

0 notes on commit e13ea3c

Please sign in to comment.
Something went wrong with that request. Please try again.