Changeset 7477
- Timestamp:
- 04/26/08 21:50:16 (1 year ago)
- Files:
-
- django/trunk/django/contrib/admin/views/main.py (modified) (4 diffs)
- django/trunk/django/contrib/contenttypes/generic.py (modified) (1 diff)
- django/trunk/django/core/exceptions.py (modified) (1 diff)
- django/trunk/django/core/management/sql.py (modified) (8 diffs)
- django/trunk/django/core/management/validation.py (modified) (8 diffs)
- django/trunk/django/core/serializers/base.py (modified) (1 diff)
- django/trunk/django/db/backends/__init__.py (modified) (6 diffs)
- django/trunk/django/db/backends/mysql/base.py (modified) (2 diffs)
- django/trunk/django/db/backends/mysql_old/base.py (modified) (2 diffs)
- django/trunk/django/db/backends/oracle/base.py (modified) (5 diffs)
- django/trunk/django/db/backends/oracle/query.py (added)
- django/trunk/django/db/backends/postgresql/operations.py (modified) (1 diff)
- django/trunk/django/db/backends/sqlite3/base.py (modified) (1 diff)
- django/trunk/django/db/__init__.py (modified) (2 diffs)
- django/trunk/django/db/models/base.py (modified) (9 diffs)
- django/trunk/django/db/models/fields/__init__.py (modified) (4 diffs)
- django/trunk/django/db/models/fields/proxy.py (added)
- django/trunk/django/db/models/fields/related.py (modified) (16 diffs)
- django/trunk/django/db/models/manager.py (modified) (6 diffs)
- django/trunk/django/db/models/options.py (modified) (10 diffs)
- django/trunk/django/db/models/query.py (modified) (18 diffs)
- django/trunk/django/db/models/query_utils.py (added)
- django/trunk/django/db/models/sql (added)
- django/trunk/django/db/models/sql/constants.py (added)
- django/trunk/django/db/models/sql/datastructures.py (added)
- django/trunk/django/db/models/sql/__init__.py (added)
- django/trunk/django/db/models/sql/query.py (added)
- django/trunk/django/db/models/sql/subqueries.py (added)
- django/trunk/django/db/models/sql/where.py (added)
- django/trunk/django/utils/tree.py (added)
- django/trunk/docs/db-api.txt (modified) (21 diffs)
- django/trunk/docs/model-api.txt (modified) (7 diffs)
- django/trunk/tests/modeltests/basic/models.py (modified) (1 diff)
- django/trunk/tests/modeltests/custom_columns/models.py (modified) (2 diffs)
- django/trunk/tests/modeltests/field_subclassing/models.py (modified) (3 diffs)
- django/trunk/tests/modeltests/lookup/models.py (modified) (3 diffs)
- django/trunk/tests/modeltests/many_to_many/models.py (modified) (1 diff)
- django/trunk/tests/modeltests/many_to_one/models.py (modified) (4 diffs)
- django/trunk/tests/modeltests/many_to_one_null/models.py (modified) (1 diff)
- django/trunk/tests/modeltests/model_inheritance/models.py (modified) (4 diffs)
- django/trunk/tests/modeltests/one_to_one/models.py (modified) (7 diffs)
- django/trunk/tests/modeltests/ordering/models.py (modified) (2 diffs)
- django/trunk/tests/modeltests/order_with_respect_to (added)
- django/trunk/tests/modeltests/order_with_respect_to/__init__.py (added)
- django/trunk/tests/modeltests/order_with_respect_to/models.py (added)
- django/trunk/tests/modeltests/or_lookups/models.py (modified) (3 diffs)
- django/trunk/tests/modeltests/reserved_names/models.py (modified) (1 diff)
- django/trunk/tests/modeltests/reverse_lookup/models.py (modified) (1 diff)
- django/trunk/tests/modeltests/select_related/models.py (modified) (6 diffs)
- django/trunk/tests/modeltests/serializers/models.py (modified) (9 diffs)
- django/trunk/tests/modeltests/signals/models.py (modified) (1 diff)
- django/trunk/tests/modeltests/transactions/models.py (modified) (1 diff)
- django/trunk/tests/modeltests/update (added)
- django/trunk/tests/modeltests/update/__init__.py (added)
- django/trunk/tests/modeltests/update/models.py (added)
- django/trunk/tests/regressiontests/null_queries/models.py (modified) (2 diffs)
- django/trunk/tests/regressiontests/queries (added)
- django/trunk/tests/regressiontests/queries/__init__.py (added)
- django/trunk/tests/regressiontests/queries/models.py (added)
- django/trunk/tests/regressiontests/serializers_regress/models.py (modified) (3 diffs)
- django/trunk/tests/regressiontests/serializers_regress/tests.py (modified) (7 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/trunk/django/contrib/admin/views/main.py
r7363 r7477 9 9 from django.shortcuts import get_object_or_404, render_to_response 10 10 from django.db import models 11 from django.db.models.query import handle_legacy_orderlist,QuerySet11 from django.db.models.query import QuerySet 12 12 from django.http import Http404, HttpResponse, HttpResponseRedirect 13 13 from django.utils.html import escape … … 628 628 # given. If not, use paginator.hits to calculate the number of objects, 629 629 # 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: 631 631 full_result_count = result_count 632 632 else: … … 654 654 def get_ordering(self): 655 655 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-specified659 # 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. 660 660 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)664 661 665 662 if ordering[0].startswith('-'): … … 754 751 or_queries = [models.Q(**{construct_search(field_name): bit}) for field_name in self.lookup_opts.admin.search_fields] 755 752 other_qs = QuerySet(self.model) 756 if qs._select_related: 757 other_qs = other_qs.select_related() 753 other_qs.dup_select_related(qs) 758 754 other_qs = other_qs.filter(reduce(operator.or_, or_queries)) 759 755 qs = qs & other_qs django/trunk/django/contrib/contenttypes/generic.py
r7422 r7477 155 155 return "ManyToManyField" 156 156 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 157 162 class ReverseGenericRelatedObjectsDescriptor(object): 158 163 """ django/trunk/django/core/exceptions.py
r6838 r7477 28 28 "Django is somehow improperly configured" 29 29 pass 30 31 class FieldError(Exception): 32 """Some kind of problem with a model field.""" 33 pass 34 django/trunk/django/core/management/sql.py
r7375 r7477 27 27 for model in models.get_models(app): 28 28 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]) 30 30 if only_existing: 31 31 existing = table_list() … … 55 55 for app in apps: 56 56 for model in models.get_models(app): 57 for f in model._meta. fields:57 for f in model._meta.local_fields: 58 58 if isinstance(f, models.AutoField): 59 59 sequence_list.append({'table': model._meta.db_table, 'column': f.column}) 60 60 break # Only one AutoField is allowed per model, so don't bother continuing. 61 61 62 for f in model._meta. many_to_many:62 for f in model._meta.local_many_to_many: 63 63 sequence_list.append({'table': f.m2m_db_table(), 'column': None}) 64 64 … … 150 150 # The table exists, so it needs to be dropped 151 151 opts = model._meta 152 for f in opts. fields:152 for f in opts.local_fields: 153 153 if f.rel and f.rel.to not in to_delete: 154 154 references_to_delete.setdefault(f.rel.to, []).append( (model, f) ) … … 182 182 for model in app_models: 183 183 opts = model._meta 184 for f in opts. many_to_many:184 for f in opts.local_many_to_many: 185 185 if isinstance(f.rel, generic.GenericRel): 186 186 continue … … 259 259 qn = connection.ops.quote_name 260 260 inline_references = connection.features.inline_fk_references 261 for f in opts. fields:261 for f in opts.local_fields: 262 262 col_type = f.db_type() 263 263 tablespace = f.db_tablespace or opts.db_tablespace … … 295 295 style.SQL_KEYWORD('NULL')) 296 296 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)' % \ 299 298 ", ".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))305 299 306 300 full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(qn(opts.db_table)) + ' ('] … … 360 354 qn = connection.ops.quote_name 361 355 inline_references = connection.features.inline_fk_references 362 for f in opts. many_to_many:356 for f in opts.local_many_to_many: 363 357 if not isinstance(f.rel, generic.GenericRel): 364 358 tablespace = f.db_tablespace or opts.db_tablespace … … 467 461 468 462 qn = connection.ops.quote_name 469 for f in model._meta. fields:463 for f in model._meta.local_fields: 470 464 if f.db_index and not ((f.primary_key or f.unique) and connection.features.autoindexes_primary_keys): 471 465 unique = f.unique and 'UNIQUE ' or '' django/trunk/django/core/management/validation.py
r7294 r7477 33 33 34 34 # Do field-specific validation. 35 for f in opts. fields:35 for f in opts.local_fields: 36 36 if f.name == 'id' and not f.primary_key and opts.pk.name == 'id': 37 37 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) … … 70 70 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]]))) 71 71 72 # Check to see if the related field will clash with any 73 # existingfields, m2m fields, m2m related objects or related objects72 # Check to see if the related field will clash with any existing 73 # fields, m2m fields, m2m related objects or related objects 74 74 if f.rel: 75 75 if f.rel.to not in models.get_models(): … … 88 88 if r.name == rel_query_name: 89 89 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: 91 91 if r.name == rel_name: 92 92 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)) … … 105 105 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)) 106 106 107 for i, f in enumerate(opts. many_to_many):107 for i, f in enumerate(opts.local_many_to_many): 108 108 # 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 110 111 if f.rel.to not in models.get_models(): 111 112 e.add(opts, "'%s' has m2m relation with model %s, which has not been installed" % (f.name, f.rel.to)) … … 118 119 rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name() 119 120 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, as123 # there areno 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. 124 125 if rel_name is not None: 125 126 for r in rel_opts.fields: … … 128 129 if r.name == rel_query_name: 129 130 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: 131 132 if r.name == rel_name: 132 133 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)) … … 201 202 if opts.order_with_respect_to and field_name == '_order': 202 203 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 204 208 try: 205 209 opts.get_field(field_name, many_to_many=False) … … 229 233 if isinstance(f.rel, models.ManyToManyRel): 230 234 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) 231 237 232 238 return len(e.errors) django/trunk/django/core/serializers/base.py
r7293 r7477 166 166 # what came from the file, not post-processed by pre_save/save 167 167 # methods. 168 models.Model.save (self.object, raw=True)168 models.Model.save_base(self.object, raw=True) 169 169 if self.m2m_data and save_m2m: 170 170 for accessor_name, object_list in self.m2m_data.items(): django/trunk/django/db/backends/__init__.py
r6650 r7477 50 50 supports_tablespaces = False 51 51 uses_case_insensitive_names = False 52 uses_custom_queryset = False 52 uses_custom_query_class = False 53 empty_fetchmany_value = [] 53 54 54 55 class BaseDatabaseOperations(object): … … 87 88 retrieved as a Python datetime object instead of a string. 88 89 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" 93 93 94 94 def deferrable_sql(self): … … 170 170 return sql 171 171 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 172 180 def max_name_length(self): 173 181 """ … … 177 185 return None 178 186 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 179 195 def pk_default_value(self): 180 196 """ … … 184 200 return 'DEFAULT' 185 201 186 def query_ set_class(self, DefaultQuerySet):202 def query_class(self, DefaultQueryClass): 187 203 """ 188 204 Given the default QuerySet class, returns a custom QuerySet class 189 205 to use for this backend. Returns None if a custom QuerySet isn't used. 190 See also BaseDatabaseFeatures.uses_custom_query set, which regulates206 See also BaseDatabaseFeatures.uses_custom_query_class, which regulates 191 207 whether this method is called at all. 192 208 """ … … 205 221 """ 206 222 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 207 234 208 235 def sql_flush(self, style, tables, sequences): django/trunk/django/db/backends/mysql/base.py
r7358 r7477 63 63 autoindexes_primary_keys = False 64 64 inline_fk_references = False 65 empty_fetchmany_value = () 65 66 66 67 class DatabaseOperations(BaseDatabaseOperations): … … 94 95 sql += "%s," % offset 95 96 return sql + str(limit) 97 98 def no_limit_value(self): 99 # 2**64 - 1, as recommended by the MySQL documentation 100 return 18446744073709551615L 96 101 97 102 def quote_name(self, name): django/trunk/django/db/backends/mysql_old/base.py
r6650 r7477 67 67 autoindexes_primary_keys = False 68 68 inline_fk_references = False 69 empty_fetchmany_value = () 69 70 70 71 class DatabaseOperations(BaseDatabaseOperations): … … 98 99 sql += "%s," % offset 99 100 return sql + str(limit) 101 102 def no_limit_value(self): 103 # 2**64 - 1, as recommended by the MySQL documentation 104 return 18446744073709551615L 100 105 101 106 def quote_name(self, name): django/trunk/django/db/backends/oracle/base.py
r7412 r7477 5 5 """ 6 6 7 import os 8 7 9 from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util 10 from django.db.backends.oracle import query 8 11 from django.utils.datastructures import SortedDict 9 12 from django.utils.encoding import smart_str, force_unicode 10 import datetime11 import os12 13 13 14 # Oracle takes client-side character set encoding from the environment. … … 25 26 allows_group_by_ordinal = False 26 27 allows_unique_and_pk = False # Suppress UNIQUE/PK for Oracle (ORA-02259) 28 empty_fetchmany_value = () 27 29 needs_datetime_string_cast = False 28 30 needs_upper_for_iops = True 29 31 supports_tablespaces = True 30 32 uses_case_insensitive_names = True 31 uses_custom_query set= True33 uses_custom_query_class = True 32 34 33 35 class DatabaseOperations(BaseDatabaseOperations): … … 90 92 return "" 91 93 94 def lookup_cast(self, lookup_type): 95 if lookup_type in ('iexact', 'icontains', 'istartswith', 'iendswith'): 96 return "UPPER(%s)" 97 return "%s" 98 92 99 def max_name_length(self): 93 100 return 30 94 101 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) 329 104 330 105 def quote_name(self, name): … … 339 114 def random_function_sql(self): 340 115 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) 341 133 342 134 def sql_flush(self, style, tables, sequences): …
