Ticket #5570: generic_relations_r6403.diff
File generic_relations_r6403.diff, 5.0 KB (added by , 17 years ago) |
---|
-
django/contrib/contenttypes/generic.py
11 11 from django.dispatch import dispatcher 12 12 from django.utils.functional import curry 13 13 14 CONTENT_TYPE_CACHE = {} 15 14 16 class GenericForeignKey(object): 15 17 """ 16 18 Provides a generic relation to any object through content-type/object-id 17 19 fields. 18 20 """ 19 21 20 22 def __init__(self, ct_field="content_type", fk_field="object_id"): 21 23 self.ct_field = ct_field 22 24 self.fk_field = fk_field 23 25 24 26 def contribute_to_class(self, cls, name): 25 27 # Make sure the fields exist (these raise FieldDoesNotExist, 26 28 # which is a fine error to raise here) 27 29 self.name = name 28 30 self.model = cls 29 31 self.cache_attr = "_%s_cache" % name 30 32 31 33 # For some reason I don't totally understand, using weakrefs here doesn't work. 32 34 dispatcher.connect(self.instance_pre_init, signal=signals.pre_init, sender=cls, weak=False) 33 35 … … 36 38 37 39 def instance_pre_init(self, signal, sender, args, kwargs): 38 40 # Handle initalizing an object with the generic FK instaed of 39 # content-type/object-id fields. 41 # content-type/object-id fields. 40 42 if self.name in kwargs: 41 43 value = kwargs.pop(self.name) 42 44 kwargs[self.ct_field] = self.get_content_type(value) 43 45 kwargs[self.fk_field] = value._get_pk_val() 44 46 45 47 def get_content_type(self, obj): 46 48 # Convenience function using get_model avoids a circular import when using this model 47 49 ContentType = get_model("contenttypes", "contenttype") 48 50 return ContentType.objects.get_for_model(obj) 49 51 50 52 def __get__(self, instance, instance_type=None): 51 53 if instance is None: 52 54 raise AttributeError, u"%s must be accessed via instance" % self.name … … 55 57 return getattr(instance, self.cache_attr) 56 58 except AttributeError: 57 59 rel_obj = None 58 ct = getattr(instance, self.ct_field) 60 ct_id_fieldname = instance._meta.get_field(self.ct_field).get_attname() 61 ct_id = getattr(instance, ct_id_fieldname) 62 try: 63 ct = CONTENT_TYPE_CACHE[ct_id] 64 except KeyError: 65 ct = getattr(instance, self.ct_field) 66 CONTENT_TYPE_CACHE[ct_id] = ct 59 67 if ct: 60 68 try: 61 69 rel_obj = ct.get_object_for_this_type(pk=getattr(instance, self.fk_field)) … … 77 85 setattr(instance, self.ct_field, ct) 78 86 setattr(instance, self.fk_field, fk) 79 87 setattr(instance, self.cache_attr, value) 80 88 81 89 class GenericRelation(RelatedField, Field): 82 90 """Provides an accessor to generic related objects (i.e. comments)""" 83 91 … … 90 98 91 99 # Override content-type/object-id field names on the related class 92 100 self.object_id_field_name = kwargs.pop("object_id_field", "object_id") 93 self.content_type_field_name = kwargs.pop("content_type_field", "content_type") 94 101 self.content_type_field_name = kwargs.pop("content_type_field", "content_type") 102 95 103 kwargs['blank'] = True 96 104 kwargs['editable'] = False 97 105 kwargs['serialize'] = False … … 116 124 117 125 def m2m_column_name(self): 118 126 return self.object_id_field_name 119 127 120 128 def m2m_reverse_name(self): 121 129 return self.object_id_field_name 122 130 … … 131 139 132 140 def contribute_to_related_class(self, cls, related): 133 141 pass 134 142 135 143 def set_attributes_from_rel(self): 136 144 pass 137 145 138 146 def get_internal_type(self): 139 147 return "ManyToManyField" 140 148 141 149 class ReverseGenericRelatedObjectsDescriptor(object): 142 150 """ 143 151 This class provides the functionality that makes the related-object … … 193 201 Factory function for a manager that subclasses 'superclass' (which is a 194 202 Manager) and adds behavior for generic related objects. 195 203 """ 196 204 197 205 class GenericRelatedObjectManager(superclass): 198 206 def __init__(self, model=None, core_filters=None, instance=None, symmetrical=None, 199 207 join_table=None, source_col_name=None, target_col_name=None, content_type=None, 200 208 content_type_field_name=None, object_id_field_name=None): 201 209 202 210 super(GenericRelatedObjectManager, self).__init__() 203 211 self.core_filters = core_filters or {} 204 212 self.model = model … … 212 220 self.content_type_field_name = content_type_field_name 213 221 self.object_id_field_name = object_id_field_name 214 222 self.pk_val = self.instance._get_pk_val() 215 223 216 224 def get_query_set(self): 217 225 query = { 218 226 '%s__pk' % self.content_type_field_name : self.content_type.id,