Changeset 8608
- Timestamp:
- 08/27/08 00:22:33 (3 months ago)
- Files:
-
- django/trunk/django/contrib/contenttypes/generic.py (modified) (1 diff)
- django/trunk/django/db/models/sql/query.py (modified) (10 diffs)
- django/trunk/tests/modeltests/generic_relations/models.py (modified) (8 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/trunk/django/contrib/contenttypes/generic.py
r8279 r8608 166 166 # same db_type as well. 167 167 return None 168 169 def extra_filters(self, pieces, pos): 170 """ 171 Return an extra filter to the queryset so that the results are filtered 172 on the appropriate content type. 173 """ 174 ContentType = get_model("contenttypes", "contenttype") 175 content_type = ContentType.objects.get_for_model(self.model) 176 prefix = "__".join(pieces[:pos + 1]) 177 return "%s__%s" % (prefix, self.content_type_field_name), content_type 168 178 169 179 class ReverseGenericRelatedObjectsDescriptor(object): django/trunk/django/db/models/sql/query.py
r8559 r8608 648 648 if not alias: 649 649 alias = self.get_initial_alias() 650 field, target, opts, joins, last = self.setup_joins(pieces, opts,651 alias, False)650 field, target, opts, joins, last, extra = self.setup_joins(pieces, 651 opts, alias, False) 652 652 alias = joins[-1] 653 653 col = target.column … … 1007 1007 1008 1008 def add_filter(self, filter_expr, connector=AND, negate=False, trim=False, 1009 can_reuse=None ):1009 can_reuse=None, process_extras=True): 1010 1010 """ 1011 1011 Add a single filter to the query. The 'filter_expr' is a pair: … … 1027 1027 if we would otherwise force the creation of new aliases for a join 1028 1028 (needed for nested Q-filters). The set is updated by this method. 1029 1030 If 'process_extras' is set, any extra filters returned from the table 1031 joining process will be processed. This parameter is set to False 1032 during the processing of extra filters to avoid infinite recursion. 1029 1033 """ 1030 1034 arg, value = filter_expr … … 1054 1058 1055 1059 try: 1056 field, target, opts, join_list, last = self.setup_joins(parts, opts,1057 alias, True, allow_many, can_reuse=can_reuse)1060 field, target, opts, join_list, last, extra_filters = self.setup_joins( 1061 parts, opts, alias, True, allow_many, can_reuse=can_reuse) 1058 1062 except MultiJoin, e: 1059 1063 self.split_exclude(filter_expr, LOOKUP_SEP.join(parts[:e.level])) … … 1153 1157 if can_reuse is not None: 1154 1158 can_reuse.update(join_list) 1159 if process_extras: 1160 for filter in extra_filters: 1161 self.add_filter(filter, negate=negate, can_reuse=can_reuse, 1162 process_extras=False) 1155 1163 1156 1164 def add_q(self, q_object, used_aliases=None): … … 1208 1216 dupe_set = set() 1209 1217 exclusions = set() 1218 extra_filters = [] 1210 1219 for pos, name in enumerate(names): 1211 1220 try: … … 1263 1272 ())) 1264 1273 1274 if hasattr(field, 'extra_filters'): 1275 extra_filters.append(field.extra_filters(names, pos)) 1265 1276 if direct: 1266 1277 if m2m: … … 1366 1377 raise FieldError("Join on field %r not permitted." % name) 1367 1378 1368 return field, target, opts, joins, last 1379 return field, target, opts, joins, last, extra_filters 1369 1380 1370 1381 def update_dupe_avoidance(self, opts, col, alias): … … 1438 1449 try: 1439 1450 for name in field_names: 1440 field, target, u2, joins, u3 = self.setup_joins(1451 field, target, u2, joins, u3, u4 = self.setup_joins( 1441 1452 name.split(LOOKUP_SEP), opts, alias, False, allow_m2m, 1442 1453 True) … … 1602 1613 opts = self.model._meta 1603 1614 alias = self.get_initial_alias() 1604 field, col, opts, joins, last = self.setup_joins(1615 field, col, opts, joins, last, extra = self.setup_joins( 1605 1616 start.split(LOOKUP_SEP), opts, alias, False) 1606 1617 alias = joins[last[-1]] django/trunk/tests/modeltests/generic_relations/models.py
r8325 r8608 83 83 >>> bacon = Vegetable(name="Bacon", is_yucky=False) 84 84 >>> quartz = Mineral(name="Quartz", hardness=7) 85 >>> for o in ( lion, platypus, eggplant, bacon, quartz):85 >>> for o in (platypus, lion, eggplant, bacon, quartz): 86 86 ... o.save() 87 87 … … 96 96 >>> lion.tags.create(tag="hairy") 97 97 <TaggedItem: hairy> 98 >>> platypus.tags.create(tag="fatty") 99 <TaggedItem: fatty> 98 100 99 101 >>> lion.tags.all() … … 125 127 >>> tag1.save() 126 128 >>> platypus.tags.all() 127 [<TaggedItem: shiny>]129 [<TaggedItem: fatty>, <TaggedItem: shiny>] 128 130 >>> TaggedItem.objects.filter(content_type__pk=ctype.id, object_id=quartz.id) 129 131 [<TaggedItem: clearish>] 132 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.filter(tags__tag='fatty') 135 [<Animal: Platypus>] 130 136 131 137 # If you delete an object with an explicit Generic relation, the related … … 133 139 # Original list of tags: 134 140 >>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()] 135 [(u'clearish', <ContentType: mineral>, 1), (u'fatty', <ContentType: vegetable>, 2), (u' hairy', <ContentType: animal>, 1), (u'salty', <ContentType: vegetable>, 2), (u'shiny', <ContentType: animal>, 2), (u'yellow', <ContentType: animal>, 1)]141 [(u'clearish', <ContentType: mineral>, 1), (u'fatty', <ContentType: vegetable>, 2), (u'fatty', <ContentType: animal>, 1), (u'hairy', <ContentType: animal>, 2), (u'salty', <ContentType: vegetable>, 2), (u'shiny', <ContentType: animal>, 1), (u'yellow', <ContentType: animal>, 2)] 136 142 137 143 >>> lion.delete() 138 144 >>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()] 139 [(u'clearish', <ContentType: mineral>, 1), (u'fatty', <ContentType: vegetable>, 2), (u' salty', <ContentType: vegetable>, 2), (u'shiny', <ContentType: animal>, 2)]145 [(u'clearish', <ContentType: mineral>, 1), (u'fatty', <ContentType: vegetable>, 2), (u'fatty', <ContentType: animal>, 1), (u'salty', <ContentType: vegetable>, 2), (u'shiny', <ContentType: animal>, 1)] 140 146 141 147 # If Generic Relation is not explicitly defined, any related objects … … 143 149 >>> quartz.delete() 144 150 >>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()] 145 [(u'clearish', <ContentType: mineral>, 1), (u'fatty', <ContentType: vegetable>, 2), (u' salty', <ContentType: vegetable>, 2), (u'shiny', <ContentType: animal>, 2)]151 [(u'clearish', <ContentType: mineral>, 1), (u'fatty', <ContentType: vegetable>, 2), (u'fatty', <ContentType: animal>, 1), (u'salty', <ContentType: vegetable>, 2), (u'shiny', <ContentType: animal>, 1)] 146 152 147 153 # If you delete a tag, the objects using the tag are unaffected … … 152 158 [<TaggedItem: salty>] 153 159 >>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()] 154 [(u'clearish', <ContentType: mineral>, 1), (u'salty', <ContentType: vegetable>, 2), (u'shiny', <ContentType: animal>, 2)] 160 [(u'clearish', <ContentType: mineral>, 1), (u'fatty', <ContentType: animal>, 1), (u'salty', <ContentType: vegetable>, 2), (u'shiny', <ContentType: animal>, 1)] 161 162 >>> TaggedItem.objects.filter(tag='fatty').delete() 155 163 156 164 >>> ctype = ContentType.objects.get_for_model(lion) … … 193 201 [<Comparison: tiger is stronger than None>] 194 202 203 195 204 # GenericInlineFormSet tests ################################################## 196 205 … … 208 217 ... print form.as_p() 209 218 <p><label for="id_generic_relations-taggeditem-content_type-object_id-0-tag">Tag:</label> <input id="id_generic_relations-taggeditem-content_type-object_id-0-tag" type="text" name="generic_relations-taggeditem-content_type-object_id-0-tag" value="shiny" maxlength="50" /></p> 210 <p><label for="id_generic_relations-taggeditem-content_type-object_id-0-DELETE">Delete:</label> <input type="checkbox" name="generic_relations-taggeditem-content_type-object_id-0-DELETE" id="id_generic_relations-taggeditem-content_type-object_id-0-DELETE" /><input type="hidden" name="generic_relations-taggeditem-content_type-object_id-0-id" value=" 5" id="id_generic_relations-taggeditem-content_type-object_id-0-id" /></p>219 <p><label for="id_generic_relations-taggeditem-content_type-object_id-0-DELETE">Delete:</label> <input type="checkbox" name="generic_relations-taggeditem-content_type-object_id-0-DELETE" id="id_generic_relations-taggeditem-content_type-object_id-0-DELETE" /><input type="hidden" name="generic_relations-taggeditem-content_type-object_id-0-id" value="..." id="id_generic_relations-taggeditem-content_type-object_id-0-id" /></p> 211 220 <p><label for="id_generic_relations-taggeditem-content_type-object_id-1-tag">Tag:</label> <input id="id_generic_relations-taggeditem-content_type-object_id-1-tag" type="text" name="generic_relations-taggeditem-content_type-object_id-1-tag" maxlength="50" /></p> 212 221 <p><label for="id_generic_relations-taggeditem-content_type-object_id-1-DELETE">Delete:</label> <input type="checkbox" name="generic_relations-taggeditem-content_type-object_id-1-DELETE" id="id_generic_relations-taggeditem-content_type-object_id-1-DELETE" /><input type="hidden" name="generic_relations-taggeditem-content_type-object_id-1-id" id="id_generic_relations-taggeditem-content_type-object_id-1-id" /></p>
