Django

Code

Changeset 7477

Show
Ignore:
Timestamp:
04/26/08 21:50:16 (1 year ago)
Author:
mtredinnick
Message:

Merged the queryset-refactor branch into trunk.

This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.

Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/django/contrib/admin/views/main.py

    r7363 r7477  
    99from django.shortcuts import get_object_or_404, render_to_response 
    1010from django.db import models 
    11 from django.db.models.query import handle_legacy_orderlist, QuerySet 
     11from django.db.models.query import QuerySet 
    1212from django.http import Http404, HttpResponse, HttpResponseRedirect 
    1313from django.utils.html import escape 
     
    628628        # given. If not, use paginator.hits to calculate the number of objects, 
    629629        # because we've already done paginator.hits and the value is cached. 
    630         if isinstance(self.query_set._filters, models.Q) and not self.query_set._filters.kwargs
     630        if not self.query_set.query.where
    631631            full_result_count = result_count 
    632632        else: 
     
    654654    def get_ordering(self): 
    655655        lookup_opts, params = self.lookup_opts, self.params 
    656         # For ordering, first check the "ordering" parameter in the admin options, 
    657         # then check the object's default ordering. If neither of those exist, 
    658         # order descending by ID by default. Finally, look for manually-specified 
    659         # ordering from the query string. 
     656        # For ordering, first check the "ordering" parameter in the admin 
     657        # options, then check the object's default ordering. If neither of 
     658        # those exist, order descending by ID by default. Finally, look for 
     659        # manually-specified ordering from the query string. 
    660660        ordering = lookup_opts.admin.ordering or lookup_opts.ordering or ['-' + lookup_opts.pk.name] 
    661  
    662         # Normalize it to new-style ordering. 
    663         ordering = handle_legacy_orderlist(ordering) 
    664661 
    665662        if ordering[0].startswith('-'): 
     
    754751                or_queries = [models.Q(**{construct_search(field_name): bit}) for field_name in self.lookup_opts.admin.search_fields] 
    755752                other_qs = QuerySet(self.model) 
    756                 if qs._select_related: 
    757                     other_qs = other_qs.select_related() 
     753                other_qs.dup_select_related(qs) 
    758754                other_qs = other_qs.filter(reduce(operator.or_, or_queries)) 
    759755                qs = qs & other_qs 
  • django/trunk/django/contrib/contenttypes/generic.py

    r7422 r7477  
    155155        return "ManyToManyField" 
    156156 
     157    def db_type(self): 
     158        # Since we're simulating a ManyToManyField, in effect, best return the 
     159        # same db_type as well. 
     160        return None 
     161 
    157162class ReverseGenericRelatedObjectsDescriptor(object): 
    158163    """ 
  • django/trunk/django/core/exceptions.py

    r6838 r7477  
    2828    "Django is somehow improperly configured" 
    2929    pass 
     30 
     31class FieldError(Exception): 
     32    """Some kind of problem with a model field.""" 
     33    pass 
     34 
  • django/trunk/django/core/management/sql.py

    r7375 r7477  
    2727        for model in models.get_models(app): 
    2828            tables.append(model._meta.db_table) 
    29             tables.extend([f.m2m_db_table() for f in model._meta.many_to_many]) 
     29            tables.extend([f.m2m_db_table() for f in model._meta.local_many_to_many]) 
    3030    if only_existing: 
    3131        existing = table_list() 
     
    5555    for app in apps: 
    5656        for model in models.get_models(app): 
    57             for f in model._meta.fields: 
     57            for f in model._meta.local_fields: 
    5858                if isinstance(f, models.AutoField): 
    5959                    sequence_list.append({'table': model._meta.db_table, 'column': f.column}) 
    6060                    break # Only one AutoField is allowed per model, so don't bother continuing. 
    6161 
    62             for f in model._meta.many_to_many: 
     62            for f in model._meta.local_many_to_many: 
    6363                sequence_list.append({'table': f.m2m_db_table(), 'column': None}) 
    6464 
     
    150150            # The table exists, so it needs to be dropped 
    151151            opts = model._meta 
    152             for f in opts.fields: 
     152            for f in opts.local_fields: 
    153153                if f.rel and f.rel.to not in to_delete: 
    154154                    references_to_delete.setdefault(f.rel.to, []).append( (model, f) ) 
     
    182182    for model in app_models: 
    183183        opts = model._meta 
    184         for f in opts.many_to_many: 
     184        for f in opts.local_many_to_many: 
    185185            if isinstance(f.rel, generic.GenericRel): 
    186186                continue 
     
    259259    qn = connection.ops.quote_name 
    260260    inline_references = connection.features.inline_fk_references 
    261     for f in opts.fields: 
     261    for f in opts.local_fields: 
    262262        col_type = f.db_type() 
    263263        tablespace = f.db_tablespace or opts.db_tablespace 
     
    295295            style.SQL_KEYWORD('NULL')) 
    296296    for field_constraints in opts.unique_together: 
    297         constraint_output = [style.SQL_KEYWORD('UNIQUE')] 
    298         constraint_output.append('(%s)' % \ 
     297        table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \ 
    299298            ", ".join([style.SQL_FIELD(qn(opts.get_field(f).column)) for f in field_constraints])) 
    300         if opts.db_tablespace and connection.features.supports_tablespaces \ 
    301                and connection.features.autoindexes_primary_keys: 
    302             constraint_output.append(connection.ops.tablespace_sql( 
    303                 opts.db_tablespace, inline=True)) 
    304         table_output.append(' '.join(constraint_output)) 
    305299 
    306300    full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(qn(opts.db_table)) + ' ('] 
     
    360354    qn = connection.ops.quote_name 
    361355    inline_references = connection.features.inline_fk_references 
    362     for f in opts.many_to_many: 
     356    for f in opts.local_many_to_many: 
    363357        if not isinstance(f.rel, generic.GenericRel): 
    364358            tablespace = f.db_tablespace or opts.db_tablespace 
     
    467461 
    468462    qn = connection.ops.quote_name 
    469     for f in model._meta.fields: 
     463    for f in model._meta.local_fields: 
    470464        if f.db_index and not ((f.primary_key or f.unique) and connection.features.autoindexes_primary_keys): 
    471465            unique = f.unique and 'UNIQUE ' or '' 
  • django/trunk/django/core/management/validation.py

    r7294 r7477  
    3333 
    3434        # Do field-specific validation. 
    35         for f in opts.fields: 
     35        for f in opts.local_fields: 
    3636            if f.name == 'id' and not f.primary_key and opts.pk.name == 'id': 
    3737                e.add(opts, '"%s": You can\'t use "id" as a field name, because each model automatically gets an "id" field if none of the fields have primary_key=True. You need to either remove/rename your "id" field or add primary_key=True to a field.' % f.name) 
     
    7070                    e.add(opts, '"%s": %s cannot have a "max_length" greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %s).' % (f.name, f.__class__.__name__, '.'.join([str(n) for n in db_version[:3]]))) 
    7171 
    72             # Check to see if the related field will clash with any 
    73             # existing fields, m2m fields, m2m related objects or related objects 
     72            # Check to see if the related field will clash with any existing 
     73            # fields, m2m fields, m2m related objects or related objects 
    7474            if f.rel: 
    7575                if f.rel.to not in models.get_models(): 
     
    8888                    if r.name == rel_query_name: 
    8989                        e.add(opts, "Reverse query name for field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) 
    90                 for r in rel_opts.many_to_many: 
     90                for r in rel_opts.local_many_to_many: 
    9191                    if r.name == rel_name: 
    9292                        e.add(opts, "Accessor for field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) 
     
    105105                            e.add(opts, "Reverse query name for field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) 
    106106 
    107         for i, f in enumerate(opts.many_to_many): 
     107        for i, f in enumerate(opts.local_many_to_many): 
    108108            # Check to see if the related m2m field will clash with any 
    109             # existing fields, m2m fields, m2m related objects or related objects 
     109            # existing fields, m2m fields, m2m related objects or related 
     110            # objects 
    110111            if f.rel.to not in models.get_models(): 
    111112                e.add(opts, "'%s' has m2m relation with model %s, which has not been installed" % (f.name, f.rel.to)) 
     
    118119            rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name() 
    119120            rel_query_name = f.related_query_name() 
    120             # If rel_name is none, there is no reverse accessor. 
    121             # (This only occurs for symmetrical m2m relations to self). 
    122             # If this is the case, there are no clashes to check for this field, as 
    123             # there are no reverse descriptors for this field. 
     121            # If rel_name is none, there is no reverse accessor (this only 
     122            # occurs for symmetrical m2m relations to self). If this is the 
     123            # case, there are no clashes to check for this field, as there are 
     124            # no reverse descriptors for this field. 
    124125            if rel_name is not None: 
    125126                for r in rel_opts.fields: 
     
    128129                    if r.name == rel_query_name: 
    129130                        e.add(opts, "Reverse query name for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) 
    130                 for r in rel_opts.many_to_many: 
     131                for r in rel_opts.local_many_to_many: 
    131132                    if r.name == rel_name: 
    132133                        e.add(opts, "Accessor for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) 
     
    201202                if opts.order_with_respect_to and field_name == '_order': 
    202203                    continue 
    203                 if '.' in field_name: continue # Skip ordering in the format 'table.field'. 
     204                # Skip ordering in the format field1__field2 (FIXME: checking 
     205                # this format would be nice, but it's a little fiddly). 
     206                if '_' in field_name: 
     207                    continue 
    204208                try: 
    205209                    opts.get_field(field_name, many_to_many=False) 
     
    229233                    if isinstance(f.rel, models.ManyToManyRel): 
    230234                        e.add(opts, '"unique_together" refers to %s. ManyToManyFields are not supported in unique_together.' % f.name) 
     235                    if f not in opts.local_fields: 
     236                        e.add(opts, '"unique_together" refers to %s. This is not in the same model as the unique_together statement.' % f.name) 
    231237 
    232238    return len(e.errors) 
  • django/trunk/django/core/serializers/base.py

    r7293 r7477  
    166166        # what came from the file, not post-processed by pre_save/save 
    167167        # methods. 
    168         models.Model.save(self.object, raw=True) 
     168        models.Model.save_base(self.object, raw=True) 
    169169        if self.m2m_data and save_m2m: 
    170170            for accessor_name, object_list in self.m2m_data.items(): 
  • django/trunk/django/db/backends/__init__.py

    r6650 r7477  
    5050    supports_tablespaces = False 
    5151    uses_case_insensitive_names = False 
    52     uses_custom_queryset = False 
     52    uses_custom_query_class = False 
     53    empty_fetchmany_value = [] 
    5354 
    5455class BaseDatabaseOperations(object): 
     
    8788        retrieved as a Python datetime object instead of a string. 
    8889 
    89         This SQL should include a '%s' in place of the field's name. This 
    90         method should return None if no casting is necessary. 
    91         """ 
    92         return None 
     90        This SQL should include a '%s' in place of the field's name. 
     91        """ 
     92        return "%s" 
    9393 
    9494    def deferrable_sql(self): 
     
    170170        return sql 
    171171 
     172    def lookup_cast(self, lookup_type): 
     173        """ 
     174        Returns the string to use in a query when performing lookups 
     175        ("contains", "like", etc). The resulting string should contain a '%s' 
     176        placeholder for the column being searched against. 
     177        """ 
     178        return "%s" 
     179 
    172180    def max_name_length(self): 
    173181        """ 
     
    177185        return None 
    178186 
     187    def no_limit_value(self): 
     188        """ 
     189        Returns the value to use for the LIMIT when we are wanting "LIMIT 
     190        infinity". Returns None if the limit clause can be omitted in this case. 
     191        """ 
     192        # FIXME: API may need to change once Oracle backend is repaired. 
     193        raise NotImplementedError() 
     194 
    179195    def pk_default_value(self): 
    180196        """ 
     
    184200        return 'DEFAULT' 
    185201 
    186     def query_set_class(self, DefaultQuerySet): 
     202    def query_class(self, DefaultQueryClass): 
    187203        """ 
    188204        Given the default QuerySet class, returns a custom QuerySet class 
    189205        to use for this backend. Returns None if a custom QuerySet isn't used. 
    190         See also BaseDatabaseFeatures.uses_custom_queryset, which regulates 
     206        See also BaseDatabaseFeatures.uses_custom_query_class, which regulates 
    191207        whether this method is called at all. 
    192208        """ 
     
    205221        """ 
    206222        return 'RANDOM()' 
     223 
     224    def regex_lookup(self, lookup_type): 
     225        """ 
     226        Returns the string to use in a query when performing regular expression 
     227        lookups (using "regex" or "iregex"). The resulting string should 
     228        contain a '%s' placeholder for the column being searched against. 
     229 
     230        If the feature is not supported (or part of it is not supported), a 
     231        NotImplementedError exception can be raised. 
     232        """ 
     233        raise NotImplementedError 
    207234 
    208235    def sql_flush(self, style, tables, sequences): 
  • django/trunk/django/db/backends/mysql/base.py

    r7358 r7477  
    6363    autoindexes_primary_keys = False 
    6464    inline_fk_references = False 
     65    empty_fetchmany_value = () 
    6566 
    6667class DatabaseOperations(BaseDatabaseOperations): 
     
    9495            sql += "%s," % offset 
    9596        return sql + str(limit) 
     97 
     98    def no_limit_value(self): 
     99        # 2**64 - 1, as recommended by the MySQL documentation 
     100        return 18446744073709551615L 
    96101 
    97102    def quote_name(self, name): 
  • django/trunk/django/db/backends/mysql_old/base.py

    r6650 r7477  
    6767    autoindexes_primary_keys = False 
    6868    inline_fk_references = False 
     69    empty_fetchmany_value = () 
    6970 
    7071class DatabaseOperations(BaseDatabaseOperations): 
     
    9899            sql += "%s," % offset 
    99100        return sql + str(limit) 
     101 
     102    def no_limit_value(self): 
     103        # 2**64 - 1, as recommended by the MySQL documentation 
     104        return 18446744073709551615L 
    100105 
    101106    def quote_name(self, name): 
  • django/trunk/django/db/backends/oracle/base.py

    r7412 r7477  
    55""" 
    66 
     7import os 
     8 
    79from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util 
     10from django.db.backends.oracle import query 
    811from django.utils.datastructures import SortedDict 
    912from django.utils.encoding import smart_str, force_unicode 
    10 import datetime 
    11 import os 
    1213 
    1314# Oracle takes client-side character set encoding from the environment. 
     
    2526    allows_group_by_ordinal = False 
    2627    allows_unique_and_pk = False        # Suppress UNIQUE/PK for Oracle (ORA-02259) 
     28    empty_fetchmany_value = () 
    2729    needs_datetime_string_cast = False 
    2830    needs_upper_for_iops = True 
    2931    supports_tablespaces = True 
    3032    uses_case_insensitive_names = True 
    31     uses_custom_queryset = True 
     33    uses_custom_query_class = True 
    3234 
    3335class DatabaseOperations(BaseDatabaseOperations): 
     
    9092        return "" 
    9193 
     94    def lookup_cast(self, lookup_type): 
     95        if lookup_type in ('iexact', 'icontains', 'istartswith', 'iendswith'): 
     96            return "UPPER(%s)" 
     97        return "%s" 
     98 
    9299    def max_name_length(self): 
    93100        return 30 
    94101 
    95     def query_set_class(self, DefaultQuerySet): 
    96         from django.db import connection 
    97         from django.db.models.query import EmptyResultSet, GET_ITERATOR_CHUNK_SIZE, quote_only_if_word 
    98  
    99         class OracleQuerySet(DefaultQuerySet): 
    100  
    101             def iterator(self): 
    102                 "Performs the SELECT database lookup of this QuerySet." 
    103  
    104                 from django.db.models.query import get_cached_row 
    105  
    106                 # self._select is a dictionary, and dictionaries' key order is 
    107                 # undefined, so we convert it to a list of tuples. 
    108                 extra_select = self._select.items() 
    109  
    110                 full_query = None 
    111  
    112                 try: 
    113                     try: 
    114                         select, sql, params, full_query = self._get_sql_clause(get_full_query=True) 
    115                     except TypeError: 
    116                         select, sql, params = self._get_sql_clause() 
    117                 except EmptyResultSet: 
    118                     raise StopIteration 
    119                 if not full_query: 
    120                     full_query = "SELECT %s%s\n%s" % ((self._distinct and "DISTINCT " or ""), ', '.join(select), sql) 
    121  
    122                 cursor = connection.cursor() 
    123                 cursor.execute(full_query, params) 
    124  
    125                 fill_cache = self._select_related 
    126                 fields = self.model._meta.fields 
    127                 index_end = len(fields) 
    128  
    129                 # so here's the logic; 
    130                 # 1. retrieve each row in turn 
    131                 # 2. convert NCLOBs 
    132  
    133                 while 1: 
    134                     rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE) 
    135                     if not rows: 
    136                         raise StopIteration 
    137                     for row in rows: 
    138                         row = self.resolve_columns(row, fields) 
    139                         if fill_cache: 
    140                             obj, index_end = get_cached_row(klass=self.model, row=row, 
    141                                                             index_start=0, max_depth=self._max_related_depth) 
    142                         else: 
    143                             obj = self.model(*row[:index_end]) 
    144                         for i, k in enumerate(extra_select): 
    145                             setattr(obj, k[0], row[index_end+i]) 
    146                         yield obj 
    147  
    148  
    149             def _get_sql_clause(self, get_full_query=False): 
    150                 from django.db.models.query import fill_table_cache, \ 
    151                     handle_legacy_orderlist, orderfield2column 
    152  
    153                 opts = self.model._meta 
    154                 qn = connection.ops.quote_name 
    155  
    156                 # Construct the fundamental parts of the query: SELECT X FROM Y WHERE Z. 
    157                 select = ["%s.%s" % (qn(opts.db_table), qn(f.column)) for f in opts.fields] 
    158                 tables = [quote_only_if_word(t) for t in self._tables] 
    159                 joins = SortedDict() 
    160                 where = self._where[:] 
    161                 params = self._params[:] 
    162  
    163                 # Convert self._filters into SQL. 
    164                 joins2, where2, params2 = self._filters.get_sql(opts) 
    165                 joins.update(joins2) 
    166                 where.extend(where2) 
    167                 params.extend(params2) 
    168  
    169                 # Add additional tables and WHERE clauses based on select_related. 
    170                 if self._select_related: 
    171                     fill_table_cache(opts, select, tables, where, opts.db_table, [opts.db_table]) 
    172  
    173                 # Add any additional SELECTs. 
    174                 if self._select: 
    175                     select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), qn(s[0])) for s in self._select.items()]) 
    176  
    177                 # Start composing the body of the SQL statement. 
    178                 sql = [" FROM", qn(opts.db_table)] 
    179  
    180                 # Compose the join dictionary into SQL describing the joins. 
    181                 if joins: 
    182                     sql.append(" ".join(["%s %s %s ON %s" % (join_type, table, alias, condition) 
    183                                     for (alias, (table, join_type, condition)) in joins.items()])) 
    184  
    185                 # Compose the tables clause into SQL. 
    186                 if tables: 
    187                     sql.append(", " + ", ".join(tables)) 
    188  
    189                 # Compose the where clause into SQL. 
    190                 if where: 
    191                     sql.append(where and "WHERE " + " AND ".join(where)) 
    192  
    193                 # ORDER BY clause 
    194                 order_by = [] 
    195                 if self._order_by is not None: 
    196                     ordering_to_use = self._order_by 
    197                 else: 
    198                     ordering_to_use = opts.ordering 
    199                 for f in handle_legacy_orderlist(ordering_to_use): 
    200                     if f == '?': # Special case. 
    201                         order_by.append(DatabaseOperations().random_function_sql()) 
    202                     else: 
    203                         if f.startswith('-'): 
    204                             col_name = f[1:] 
    205                             order = "DESC" 
    206                         else: 
    207                             col_name = f 
    208                             order = "ASC" 
    209                         if "." in col_name: 
    210                             table_prefix, col_name = col_name.split('.', 1) 
    211                             table_prefix = qn(table_prefix) + '.' 
    212                         else: 
    213                             # Use the database table as a column prefix if it wasn't given, 
    214                             # and if the requested column isn't a custom SELECT. 
    215                             if "." not in col_name and col_name not in (self._select or ()): 
    216                                 table_prefix = qn(opts.db_table) + '.' 
    217                             else: 
    218                                 table_prefix = '' 
    219                         order_by.append('%s%s %s' % (table_prefix, qn(orderfield2column(col_name, opts)), order)) 
    220                 if order_by: 
    221                     sql.append("ORDER BY " + ", ".join(order_by)) 
    222  
    223                 # Look for column name collisions in the select elements 
    224                 # and fix them with an AS alias.  This allows us to do a 
    225                 # SELECT * later in the paging query. 
    226                 cols = [clause.split('.')[-1] for clause in select] 
    227                 for index, col in enumerate(cols): 
    228                     if cols.count(col) > 1: 
    229                         col = '%s%d' % (col.replace('"', ''), index) 
    230                         cols[index] = col 
    231                         select[index] = '%s AS %s' % (select[index], col) 
    232  
    233                 # LIMIT and OFFSET clauses 
    234                 # To support limits and offsets, Oracle requires some funky rewriting of an otherwise normal looking query. 
    235                 select_clause = ",".join(select) 
    236                 distinct = (self._distinct and "DISTINCT " or "") 
    237  
    238                 if order_by: 
    239                     order_by_clause = " OVER (ORDER BY %s )" % (", ".join(order_by)) 
    240                 else: 
    241                     #Oracle's row_number() function always requires an order-by clause. 
    242                     #So we need to define a default order-by, since none was provided. 
    243                     order_by_clause = " OVER (ORDER BY %s.%s)" % \ 
    244                         (qn(opts.db_table), qn(opts.fields[0].db_column or opts.fields[0].column)) 
    245                 # limit_and_offset_clause 
    246                 if self._limit is None: 
    247                     assert self._offset is None, "'offset' is not allowed without 'limit'" 
    248  
    249                 if self._offset is not None: 
    250                     offset = int(self._offset) 
    251                 else: 
    252                     offset = 0 
    253                 if self._limit is not None: 
    254                     limit = int(self._limit) 
    255                 else: 
    256                     limit = None 
    257  
    258                 limit_and_offset_clause = '' 
    259                 if limit is not None: 
    260                     limit_and_offset_clause = "WHERE rn > %s AND rn <= %s" % (offset, limit+offset) 
    261                 elif offset: 
    262                     limit_and_offset_clause = "WHERE rn > %s" % (offset) 
    263  
    264                 if len(limit_and_offset_clause) > 0: 
    265                     fmt = \ 
    266     """SELECT * FROM 
    267       (SELECT %s%s, 
    268               ROW_NUMBER()%s AS rn 
    269        %s) 
    270     %s""" 
    271                     full_query = fmt % (distinct, select_clause, 
    272                                         order_by_clause, ' '.join(sql).strip(), 
    273                                         limit_and_offset_clause) 
    274                 else: 
    275                     full_query = None 
    276  
    277                 if get_full_query: 
    278                     return select, " ".join(sql), params, full_query 
    279                 else: 
    280                     return select, " ".join(sql), params 
    281  
    282             def resolve_columns(self, row, fields=()): 
    283                 from django.db.models.fields import DateField, DateTimeField, \ 
    284                     TimeField, BooleanField, NullBooleanField, DecimalField, Field 
    285                 values = [] 
    286                 for value, field in map(None, row, fields): 
    287                     if isinstance(value, Database.LOB): 
    288                         value = value.read() 
    289                     # Oracle stores empty strings as null. We need to undo this in 
    290                     # order to adhere to the Django convention of using the empty 
    291                     # string instead of null, but only if the field accepts the 
    292                     # empty string. 
    293                     if value is None and isinstance(field, Field) and field.empty_strings_allowed: 
    294                         value = u'' 
    295                     # Convert 1 or 0 to True or False 
    296                     elif value in (1, 0) and isinstance(field, (BooleanField, NullBooleanField)): 
    297                         value = bool(value) 
    298                     # Convert floats to decimals 
    299                     elif value is not None and isinstance(field, DecimalField): 
    300                         value = util.typecast_decimal(field.format_number(value)) 
    301                     # cx_Oracle always returns datetime.datetime objects for 
    302                     # DATE and TIMESTAMP columns, but Django wants to see a 
    303                     # python datetime.date, .time, or .datetime.  We use the type 
    304                     # of the Field to determine which to cast to, but it's not 
    305                     # always available. 
    306                     # As a workaround, we cast to date if all the time-related 
    307                     # values are 0, or to time if the date is 1/1/1900. 
    308                     # This could be cleaned a bit by adding a method to the Field 
    309                     # classes to normalize values from the database (the to_python 
    310                     # method is used for validation and isn't what we want here). 
    311                     elif isinstance(value, Database.Timestamp): 
    312                         # In Python 2.3, the cx_Oracle driver returns its own 
    313                         # Timestamp object that we must convert to a datetime class. 
    314                         if not isinstance(value, datetime.datetime): 
    315                             value = datetime.datetime(value.year, value.month, value.day, value.hour, 
    316                                                       value.minute, value.second, value.fsecond) 
    317                         if isinstance(field, DateTimeField): 
    318                             pass  # DateTimeField subclasses DateField so must be checked first. 
    319                         elif isinstance(field, DateField): 
    320                             value = value.date() 
    321                         elif isinstance(field, TimeField) or (value.year == 1900 and value.month == value.day == 1): 
    322                             value = value.time() 
    323                         elif value.hour == value.minute == value.second == value.microsecond == 0: 
    324                             value = value.date() 
    325                     values.append(value) 
    326                 return values 
    327  
    328         return OracleQuerySet 
     102    def query_class(self, DefaultQueryClass): 
     103        return query.query_class(DefaultQueryClass, Database) 
    329104 
    330105    def quote_name(self, name): 
     
    339114    def random_function_sql(self): 
    340115        return "DBMS_RANDOM.RANDOM" 
     116 
     117    def regex_lookup_9(self, lookup_type): 
     118        raise NotImplementedError("Regexes are not supported in Oracle before version 10g.") 
     119 
     120    def regex_lookup_10(self, lookup_type): 
     121        if lookup_type == 'regex': 
     122            match_option = "'c'" 
     123        else: 
     124            match_option = "'i'" 
     125        return 'REGEXP_LIKE(%%s, %%s, %s)' % match_option 
     126 
     127    def regex_lookup(self, lookup_type): 
     128        # If regex_lookup is called before it's been initialized, then create 
     129        # a cursor to initialize it and recur. 
     130        from django.db import connection 
     131        connection.cursor() 
     132        return connection.ops.regex_lookup(lookup_type) 
    341133 
    342134    def sql_flush(self, style, tables, sequences):