Changeset 8644
- Timestamp:
- 08/28/08 00:00:23 (3 months ago)
- Files:
-
- django/trunk/django/contrib/contenttypes/generic.py (modified) (1 diff)
- django/trunk/django/db/models/sql/query.py (modified) (8 diffs)
- django/trunk/tests/modeltests/generic_relations/models.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/trunk/django/contrib/contenttypes/generic.py
r8616 r8644 158 158 return None 159 159 160 def extra_filters(self, pieces, pos ):160 def extra_filters(self, pieces, pos, negate): 161 161 """ 162 162 Return an extra filter to the queryset so that the results are filtered 163 163 on the appropriate content type. 164 164 """ 165 if negate: 166 return [] 165 167 ContentType = get_model("contenttypes", "contenttype") 166 168 content_type = ContentType.objects.get_for_model(self.model) 167 169 prefix = "__".join(pieces[:pos + 1]) 168 return "%s__%s" % (prefix, self.content_type_field_name), content_type 170 return [("%s__%s" % (prefix, self.content_type_field_name), 171 content_type)] 169 172 170 173 class ReverseGenericRelatedObjectsDescriptor(object): django/trunk/django/db/models/sql/query.py
r8608 r8644 1059 1059 try: 1060 1060 field, target, opts, join_list, last, extra_filters = self.setup_joins( 1061 parts, opts, alias, True, allow_many, can_reuse=can_reuse) 1061 parts, opts, alias, True, allow_many, can_reuse=can_reuse, 1062 negate=negate, process_extras=process_extras) 1062 1063 except MultiJoin, e: 1063 self.split_exclude(filter_expr, LOOKUP_SEP.join(parts[:e.level])) 1064 self.split_exclude(filter_expr, LOOKUP_SEP.join(parts[:e.level]), 1065 can_reuse) 1064 1066 return 1065 1067 final = len(join_list) … … 1197 1199 1198 1200 def setup_joins(self, names, opts, alias, dupe_multis, allow_many=True, 1199 allow_explicit_fk=False, can_reuse=None): 1201 allow_explicit_fk=False, can_reuse=None, negate=False, 1202 process_extras=True): 1200 1203 """ 1201 1204 Compute the necessary table joins for the passage through the fields … … 1206 1209 disjunctive filters). If can_reuse is not None, it's a list of aliases 1207 1210 that can be reused in these joins (nothing else can be reused in this 1208 case). 1211 case). Finally, 'negate' is used in the same sense as for add_filter() 1212 -- it indicates an exclude() filter, or something similar. It is only 1213 passed in here so that it can be passed to a field's extra_filter() for 1214 customised behaviour. 1209 1215 1210 1216 Returns the final field involved in the join, the target database … … 1272 1278 ())) 1273 1279 1274 if hasattr(field, 'extra_filters'):1275 extra_filters. append(field.extra_filters(names, pos))1280 if process_extras and hasattr(field, 'extra_filters'): 1281 extra_filters.extend(field.extra_filters(names, pos, negate)) 1276 1282 if direct: 1277 1283 if m2m: … … 1296 1302 dupe_multis, exclusions, nullable=True, 1297 1303 reuse=can_reuse) 1298 alias = self.join((int_alias, table2, from_col2, to_col2), 1299 dupe_multis, exclusions, nullable=True, 1300 reuse=can_reuse) 1301 joins.extend([int_alias, alias]) 1304 if int_alias == table2 and from_col2 == to_col2: 1305 joins.append(int_alias) 1306 alias = int_alias 1307 else: 1308 alias = self.join( 1309 (int_alias, table2, from_col2, to_col2), 1310 dupe_multis, exclusions, nullable=True, 1311 reuse=can_reuse) 1312 joins.extend([int_alias, alias]) 1302 1313 elif field.rel: 1303 1314 # One-to-one or many-to-one field … … 1392 1403 self.dupe_avoidance[ident, name] = set([alias]) 1393 1404 1394 def split_exclude(self, filter_expr, prefix ):1405 def split_exclude(self, filter_expr, prefix, can_reuse): 1395 1406 """ 1396 1407 When doing an exclude against any kind of N-to-many relation, we need … … 1400 1411 """ 1401 1412 query = Query(self.model, self.connection) 1402 query.add_filter(filter_expr )1413 query.add_filter(filter_expr, can_reuse=can_reuse) 1403 1414 query.set_start(prefix) 1404 1415 query.clear_ordering(True) 1405 self.add_filter(('%s__in' % prefix, query), negate=True, trim=True) 1416 self.add_filter(('%s__in' % prefix, query), negate=True, trim=True, 1417 can_reuse=can_reuse) 1406 1418 1407 1419 def set_limits(self, low=None, high=None): … … 1615 1627 field, col, opts, joins, last, extra = self.setup_joins( 1616 1628 start.split(LOOKUP_SEP), opts, alias, False) 1629 self.unref_alias(alias) 1617 1630 alias = joins[last[-1]] 1618 1631 self.select = [(alias, self.alias_map[alias][RHS_JOIN_COL])] django/trunk/tests/modeltests/generic_relations/models.py
r8608 r8644 132 132 133 133 # Queries across generic relations respect the content types. Even though there are two TaggedItems with a tag of "fatty", this query only pulls out the one with the content type related to Animals. 134 >>> Animal.objects.order_by('common_name') 135 [<Animal: Lion>, <Animal: Platypus>] 134 136 >>> Animal.objects.filter(tags__tag='fatty') 135 137 [<Animal: Platypus>] 138 >>> Animal.objects.exclude(tags__tag='fatty') 139 [<Animal: Lion>] 136 140 137 141 # If you delete an object with an explicit Generic relation, the related
