Django

Code

Changeset 7427

Show
Ignore:
Timestamp:
04/15/08 21:58:26 (7 months ago)
Author:
mtredinnick
Message:

queryset-refactor: The Oracle changes necessary for [7426]. I can't test these
at the moment, but they should be close to correct.

Refs #6956.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/queryset-refactor/django/db/backends/__init__.py

    r7283 r7427  
    5050    supports_tablespaces = False 
    5151    uses_case_insensitive_names = False 
    52     uses_custom_queryset = False 
     52    uses_custom_query_class = False 
    5353    empty_fetchmany_value = [] 
    5454 
     
    200200        return 'DEFAULT' 
    201201 
    202     def query_set_class(self, DefaultQuerySet): 
     202    def query_class(self, DefaultQueryClass): 
    203203        """ 
    204204        Given the default QuerySet class, returns a custom QuerySet class 
    205205        to use for this backend. Returns None if a custom QuerySet isn't used. 
    206         See also BaseDatabaseFeatures.uses_custom_queryset, which regulates 
     206        See also BaseDatabaseFeatures.uses_custom_query_class, which regulates 
    207207        whether this method is called at all. 
    208208        """ 
  • django/branches/queryset-refactor/django/db/backends/oracle/base.py

    r7416 r7427  
    55""" 
    66 
    7 import datetime 
    87import os 
    98 
    109from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util 
     10from django.db.backends.oracle import query 
    1111from django.utils.datastructures import SortedDict 
    1212from django.utils.encoding import smart_str, force_unicode 
     
    3131    supports_tablespaces = True 
    3232    uses_case_insensitive_names = True 
    33     uses_custom_queryset = True 
     33    uses_custom_query_class = True 
    3434 
    3535class DatabaseOperations(BaseDatabaseOperations): 
     
    100100        return 30 
    101101 
    102     def query_set_class(self, DefaultQuerySet): 
    103         # Getting the base default `Query` object. 
    104         DefaultQuery = DefaultQuerySet().query.__class__ 
    105  
    106         class OracleQuery(DefaultQuery): 
    107             def resolve_columns(self, row, fields=()): 
    108                 from django.db.models.fields import DateField, DateTimeField, \ 
    109                      TimeField, BooleanField, NullBooleanField, DecimalField, Field 
    110                 values = [] 
    111                 for value, field in map(None, row, fields): 
    112                     if isinstance(value, Database.LOB): 
    113                         value = value.read() 
    114                     # Oracle stores empty strings as null. We need to undo this in 
    115                     # order to adhere to the Django convention of using the empty 
    116                     # string instead of null, but only if the field accepts the 
    117                     # empty string. 
    118                     if value is None and isinstance(field, Field) and field.empty_strings_allowed: 
    119                         value = u'' 
    120                     # Convert 1 or 0 to True or False 
    121                     elif value in (1, 0) and isinstance(field, (BooleanField, NullBooleanField)): 
    122                         value = bool(value) 
    123                     # Convert floats to decimals 
    124                     elif value is not None and isinstance(field, DecimalField): 
    125                         value = util.typecast_decimal(field.format_number(value)) 
    126                     # cx_Oracle always returns datetime.datetime objects for 
    127                     # DATE and TIMESTAMP columns, but Django wants to see a 
    128                     # python datetime.date, .time, or .datetime.  We use the type 
    129                     # of the Field to determine which to cast to, but it's not 
    130                     # always available. 
    131                     # As a workaround, we cast to date if all the time-related 
    132                     # values are 0, or to time if the date is 1/1/1900. 
    133                     # This could be cleaned a bit by adding a method to the Field 
    134                     # classes to normalize values from the database (the to_python 
    135                     # method is used for validation and isn't what we want here). 
    136                     elif isinstance(value, Database.Timestamp): 
    137                         # In Python 2.3, the cx_Oracle driver returns its own 
    138                         # Timestamp object that we must convert to a datetime class. 
    139                         if not isinstance(value, datetime.datetime): 
    140                             value = datetime.datetime(value.year, value.month, value.day, value.hour, 
    141                                                       value.minute, value.second, value.fsecond) 
    142                         if isinstance(field, DateTimeField): 
    143                             pass  # DateTimeField subclasses DateField so must be checked first. 
    144                         elif isinstance(field, DateField): 
    145                             value = value.date() 
    146                         elif isinstance(field, TimeField) or (value.year == 1900 and value.month == value.day == 1): 
    147                             value = value.time() 
    148                         elif value.hour == value.minute == value.second == value.microsecond == 0: 
    149                             value = value.date() 
    150                     values.append(value) 
    151                 return values 
    152  
    153             def as_sql(self, with_limits=True): 
    154                 """ 
    155                 Creates the SQL for this query. Returns the SQL string and list 
    156                 of parameters.  This is overriden from the original Query class 
    157                 to accommodate Oracle's limit/offset SQL. 
    158  
    159                 If 'with_limits' is False, any limit/offset information is not 
    160                 included in the query. 
    161                 """ 
    162                 # The `do_offset` flag indicates whether we need to construct 
    163                 # the SQL needed to use limit/offset w/Oracle. 
    164                 do_offset = with_limits and (self.high_mark or self.low_mark) 
    165  
    166                 # If no offsets, just return the result of the base class 
    167                 # `as_sql`. 
    168                 if not do_offset: 
    169                     return super(OracleQuery, self).as_sql(with_limits=False) 
    170  
    171                 # `get_columns` needs to be called before `get_ordering` to 
    172                 # populate `_select_alias`. 
    173                 self.pre_sql_setup() 
    174                 out_cols = self.get_columns() 
    175                 ordering = self.get_ordering() 
    176  
    177                 # Getting the "ORDER BY" SQL for the ROW_NUMBER() result. 
    178                 if ordering: 
    179                     rn_orderby = ', '.join(ordering) 
    180                 else: 
    181                     # Oracle's ROW_NUMBER() function always requires an 
    182                     # order-by clause.  So we need to define a default 
    183                     # order-by, since none was provided. 
    184                     qn = self.quote_name_unless_alias 
    185                     opts = self.model._meta 
    186                     rn_orderby = '%s.%s' % (qn(opts.db_table), qn(opts.fields[0].db_column or opts.fields[0].column)) 
    187  
    188                 # Getting the selection SQL and the params, which has the `rn` 
    189                 # extra selection SQL; we pop `rn` after this completes so we do 
    190                 # not get the attribute on the returned models. 
    191                 self.extra_select['rn'] = 'ROW_NUMBER() OVER (ORDER BY %s )' % rn_orderby 
    192                 sql, params= super(OracleQuery, self).as_sql(with_limits=False) 
    193                 self.extra_select.pop('rn') 
    194  
    195                 # Constructing the result SQL, using the initial select SQL 
    196                 # obtained above. 
    197                 result = ['SELECT * FROM (%s)' % sql] 
    198  
    199                 # Place WHERE condition on `rn` for the desired range. 
    200                 result.append('WHERE rn > %d' % self.low_mark) 
    201                 if self.high_mark: 
    202                     result.append('AND rn <= %d' % self.high_mark) 
    203  
    204                 # Returning the SQL w/params. 
    205                 return ' '.join(result), params 
    206  
    207         from django.db import connection 
    208         class OracleQuerySet(DefaultQuerySet): 
    209             "The OracleQuerySet is overriden to use OracleQuery." 
    210             def __init__(self, model=None, query=None): 
    211                 super(OracleQuerySet, self).__init__(model=model, query=query) 
    212                 self.query = query or OracleQuery(self.model, connection) 
    213         return OracleQuerySet 
     102    def query_class(self, DefaultQueryClass): 
     103        return query.query_class(DefaultQueryClass, Database) 
    214104 
    215105    def quote_name(self, name):