Changeset 1508
- Timestamp:
- 11/30/05 00:14:05 (3 years ago)
- Files:
-
- django/trunk/django/contrib/admin/views/main.py (modified) (1 diff)
- django/trunk/django/core/meta/__init__.py (modified) (2 diffs)
- django/trunk/docs/db-api.txt (modified) (1 diff)
- django/trunk/tests/testapp/models/__init__.py (modified) (1 diff)
- django/trunk/tests/testapp/models/or_lookups.py (added)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/trunk/django/contrib/admin/views/main.py
r1507 r1508 217 217 lookup_params['order_by'] = ((order_type == 'desc' and '-' or '') + lookup_order_field,) 218 218 if lookup_opts.admin.search_fields and query: 219 or_queries = []219 complex_queries = [] 220 220 for bit in query.split(): 221 or_quer y= []221 or_queries = [] 222 222 for field_name in lookup_opts.admin.search_fields: 223 or_query.append(('%s__icontains' % field_name, bit)) 224 or_queries.append(or_query) 225 lookup_params['_or'] = or_queries 226 223 or_queries.append(meta.Q(**{'%s__icontains' % field_name: bit})) 224 complex_queries.append(reduce(operator.or_, or_queries)) 225 lookup_params['complex'] = reduce(operator.and_, complex_queries) 227 226 if opts.one_to_one_field: 228 227 lookup_params.update(opts.one_to_one_field.rel.limit_choices_to) 229 228 self.lookup_params = lookup_params 230 231 229 232 230 def change_list(request, app_label, module_name): django/trunk/django/core/meta/__init__.py
r1504 r1508 282 282 rel_obj_name = '%s_%s' % (self.opts.app_label, rel_obj_name) 283 283 return rel_obj_name 284 285 class QBase: 286 "Base class for QAnd and QOr" 287 def __init__(self, *args): 288 self.args = args 289 290 def __repr__(self): 291 return '(%s)' % self.operator.join([repr(el) for el in self.args]) 292 293 def get_sql(self, opts, table_count): 294 tables, join_where, where, params = [], [], [], [] 295 for val in self.args: 296 tables2, join_where2, where2, params2, table_count = val.get_sql(opts, table_count) 297 tables.extend(tables2) 298 join_where.extend(join_where2) 299 where.extend(where2) 300 params.extend(params2) 301 return tables, join_where, ['(%s)' % self.operator.join(where)], params, table_count 302 303 class QAnd(QBase): 304 "Encapsulates a combined query that uses 'AND'." 305 operator = ' AND ' 306 def __or__(self, other): 307 if isinstance(other, (QAnd, QOr, Q)): 308 return QOr(self, other) 309 else: 310 raise TypeError, other 311 312 def __and__(self, other): 313 if isinstance(other, QAnd): 314 return QAnd(*(self.args+other.args)) 315 elif isinstance(other, (Q, QOr)): 316 return QAnd(*(self.args+(other,))) 317 else: 318 raise TypeError, other 319 320 class QOr(QBase): 321 "Encapsulates a combined query that uses 'OR'." 322 operator = ' OR ' 323 def __and__(self, other): 324 if isinstance(other, (QAnd, QOr, Q)): 325 return QAnd(self, other) 326 else: 327 raise TypeError, other 328 329 def __or__(self, other): 330 if isinstance(other, QOr): 331 return QOr(*(self.args+other.args)) 332 elif isinstance(other, (Q, QAnd)): 333 return QOr(*(self.args+(other,))) 334 else: 335 raise TypeError, other 336 337 class Q: 338 "Encapsulates queries for the 'complex' parameter to Django API functions." 339 def __init__(self, **kwargs): 340 self.kwargs = kwargs 341 342 def __repr__(self): 343 return 'Q%r' % self.kwargs 344 345 def __and__(self, other): 346 if isinstance(other, (Q, QAnd, QOr)): 347 return QAnd(self, other) 348 else: 349 raise TypeError, other 350 351 def __or__(self, other): 352 if isinstance(other, (Q, QAnd, QOr)): 353 return QOr(self, other) 354 else: 355 raise TypeError, other 356 357 def get_sql(self, opts, table_count): 358 return _parse_lookup(self.kwargs.items(), opts, table_count) 284 359 285 360 class Options: … … 1390 1465 continue 1391 1466 if kwarg_value is None: 1467 continue 1468 if kwarg == 'complex': 1469 tables2, join_where2, where2, params2, table_count = kwarg_value.get_sql(opts, table_count) 1470 tables.extend(tables2) 1471 join_where.extend(join_where2) 1472 where.extend(where2) 1473 params.extend(params2) 1392 1474 continue 1393 1475 if kwarg == '_or': django/trunk/docs/db-api.txt
r1352 r1508 220 220 .. _`Keyword Arguments`: http://docs.python.org/tut/node6.html#SECTION006720000000000000000 221 221 222 OR lookups 223 ---------- 224 225 **New in Django development version.** 226 227 By default, multiple lookups are "AND"ed together. If you'd like to use ``OR`` 228 statements in your queries, use the ``complex`` lookup type. 229 230 ``complex`` takes an expression of clauses, each of which is an instance of 231 ``django.core.meta.Q``. ``Q`` takes an arbitrary number of keyword arguments in 232 the standard Django lookup format. And you can use Python's "and" (``&``) and 233 "or" (``|``) operators to combine ``Q`` instances. For example:: 234 235 from django.core.meta import Q 236 polls.get_object(complex=(Q(question__startswith='Who') | Q(question__startswith='What'))) 237 238 The ``|`` symbol signifies an "OR", so this (roughly) translates into:: 239 240 SELECT * FROM polls 241 WHERE question LIKE 'Who%' OR question LIKE 'What%'; 242 243 You can use ``&`` and ``|`` operators together, and use parenthetical grouping. 244 Example:: 245 246 polls.get_object(complex=(Q(question__startswith='Who') & (Q(pub_date__exact=date(2005, 5, 2)) | pub_date__exact=date(2005, 5, 6))) 247 248 This roughly translates into:: 249 250 SELECT * FROM polls 251 WHERE question LIKE 'Who%' 252 AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06'); 253 254 See the `OR lookups examples page`_ for more examples. 255 256 .. _OR lookups examples page: http://www.djangoproject.com/documentation/models/or_lookups/ 257 222 258 Ordering 223 259 ======== django/trunk/tests/testapp/models/__init__.py
r1224 r1508 2 2 'ordering', 'lookup', 'get_latest', 'm2m_intermediary', 'one_to_one', 3 3 'm2o_recursive', 'm2o_recursive2', 'save_delete_hooks', 'custom_pk', 4 'subclassing', 'many_to_one_null', 'custom_columns', 'reserved_names'] 4 'subclassing', 'many_to_one_null', 'custom_columns', 'reserved_names', 5 'or_lookups']
