Changeset 2409
- Timestamp:
- 02/27/06 08:23:52 (3 years ago)
- Files:
-
- django/branches/magic-removal/django/db/models/fields/related.py (modified) (12 diffs)
- django/branches/magic-removal/django/db/models/manager.py (modified) (1 diff)
- django/branches/magic-removal/tests/modeltests/many_to_many/models.py (modified) (2 diffs)
- django/branches/magic-removal/tests/modeltests/many_to_one/models.py (modified) (2 diffs)
- django/branches/magic-removal/tests/modeltests/many_to_one_null/models.py (modified) (1 diff)
- django/branches/magic-removal/tests/modeltests/mutually_referential/models.py (modified) (1 diff)
- django/branches/magic-removal/tests/modeltests/one_to_one/models.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/branches/magic-removal/django/db/models/fields/related.py
r2385 r2409 98 98 other_field = self._field.rel.get_related_field() 99 99 if other_field.rel: 100 params = {'%s__ %s__exact' % (self._field.rel.field_name, other_field.rel.field_name): val}100 params = {'%s__pk' % self._field.rel.field_name: val} 101 101 else: 102 102 params = {'%s__exact' % self._field.rel.field_name: val} … … 105 105 return rel_obj 106 106 107 class ForeignRelatedObjectsDescriptor(object): 108 # This class provides the functionality that makes the related-object 109 # managers available as attributes on a model class, for fields that have 110 # multiple "remote" values and have a ForeignKey pointed at them by 111 # some other model. In the example "poll.choice_set", the choice_set 112 # attribute is a ForeignRelatedObjectsDescriptor instance. 113 def __init__(self, related): 114 self.related = related # RelatedObject instance 115 116 def __get__(self, instance, instance_type=None): 117 if instance is None: 118 raise AttributeError, "Manager must be accessed via instance" 119 120 rel_field = self.related.field 121 rel_model = self.related.model 122 123 # Dynamically create a class that subclasses the related 124 # model's default manager. 125 superclass = self.related.model._default_manager.__class__ 126 127 class RelatedManager(superclass): 128 def get_query_set(self): 129 return superclass.get_query_set(self).filter(**(self.core_filters)) 130 131 def add(self, *objs): 132 for obj in objs: 133 val = getattr(instance, rel_field.rel.get_related_field().attname) 134 setattr(obj, rel_field.attname, val) 135 obj.save() 136 add.alters_data = True 137 138 def create(self, **kwargs): 139 new_obj = self.model(**kwargs) 140 self.add(new_obj) 141 return new_obj 142 create.alters_data = True 143 144 manager = RelatedManager() 145 manager.core_filters = {'%s__pk' % rel_field.name: getattr(instance, rel_field.rel.get_related_field().attname)} 146 manager.model = self.related.model 147 148 return manager 149 107 150 def _add_m2m_items(rel_manager_inst, managerclass, rel_model, join_table, source_col_name, 108 target_col_name, source_pk_val, *objs , **kwargs):151 target_col_name, source_pk_val, *objs): 109 152 # Utility function used by the ManyRelatedObjectsDescriptors 110 153 # to do addition to a many-to-many field. … … 116 159 # target_col_name: the PK colname in join_table for the target object 117 160 # source_pk_val: the primary key for the source object 118 # *objs - objects to add , or **kwargs to create new objects161 # *objs - objects to add 119 162 120 163 from django.db import connection 121 164 rel_opts = rel_model._meta 122 # Create the related object.123 if kwargs:124 assert len(objs) == 0, "add() can't be passed both positional and keyword arguments"125 objs = [managerclass.add(rel_manager_inst, **kwargs)]126 else:127 assert len(objs) > 0, "add() must be passed either positional or keyword arguments"128 for obj in objs:129 if not isinstance(obj, rel_model):130 raise ValueError, "positional arguments to add() must be %s instances" % rel_opts.object_name131 165 132 166 # Add the newly created or already existing objects to the join table. … … 192 226 # multiple "remote" values and have a ManyToManyField pointed at them by 193 227 # some other model (rather than having a ManyToManyField themselves). 194 # In the example "p oll.choice_set", the choice_set attribute is a228 # In the example "publication.article_set", the article_set attribute is a 195 229 # ManyRelatedObjectsDescriptor instance. 196 def __init__(self, related , rel_type):230 def __init__(self, related): 197 231 self.related = related # RelatedObject instance 198 self.rel_type = rel_type # Either 'o2m' or 'm2m'199 232 200 233 def __get__(self, instance, instance_type=None): … … 203 236 204 237 rel_field = self.related.field 205 rel_type = self.rel_type206 238 rel_model = self.related.model 207 239 208 if rel_type == "m2m": 209 qn = backend.quote_name 210 this_opts = instance.__class__._meta 211 rel_opts = rel_model._meta 212 join_table = qn(self.related.field.m2m_db_table()) 213 source_col_name = qn(self.related.field.m2m_reverse_name()) 214 target_col_name = qn(self.related.field.m2m_column_name()) 240 qn = backend.quote_name 241 this_opts = instance.__class__._meta 242 rel_opts = rel_model._meta 243 join_table = qn(self.related.field.m2m_db_table()) 244 source_col_name = qn(self.related.field.m2m_reverse_name()) 245 target_col_name = qn(self.related.field.m2m_column_name()) 215 246 216 247 # Dynamically create a class that subclasses the related … … 222 253 return superclass.get_query_set(self).filter(**(self.core_filters)) 223 254 224 if rel_type == "o2m": 225 def add(self, **kwargs): 226 kwargs.update({rel_field.name: instance}) 227 return superclass.add(self, **kwargs) 228 else: 229 def add(self, *objs, **kwargs): 230 _add_m2m_items(self, superclass, rel_model, join_table, source_col_name, 231 target_col_name, instance._get_pk_val(), *objs, **kwargs) 255 def add(self, *objs): 256 _add_m2m_items(self, superclass, rel_model, join_table, source_col_name, 257 target_col_name, instance._get_pk_val(), *objs) 232 258 add.alters_data = True 233 259 234 if rel_type == "o2m": 235 def remove(self, *objs): 236 pass # TODO 237 else: 238 def remove(self, *objs): 239 _remove_m2m_items(rel_model, join_table, source_col_name, 240 target_col_name, instance._get_pk_val(), *objs) 260 def remove(self, *objs): 261 _remove_m2m_items(rel_model, join_table, source_col_name, 262 target_col_name, instance._get_pk_val(), *objs) 241 263 remove.alters_data = True 242 264 243 if rel_type == "o2m": 244 def clear(self): 245 pass # TODO 246 else: 247 def clear(self): 248 _clear_m2m_items(join_table, source_col_name, instance._get_pk_val()) 265 def clear(self): 266 _clear_m2m_items(join_table, source_col_name, instance._get_pk_val()) 249 267 clear.alters_data = True 250 268 269 def create(self, **kwargs): 270 new_obj = self.model(**kwargs) 271 new_obj.save() 272 self.add(new_obj) 273 return new_obj 274 create.alters_data = True 275 251 276 manager = RelatedManager() 252 253 if self.rel_type == 'o2m': 254 manager.core_filters = {'%s__pk' % rel_field.name: getattr(instance, rel_field.rel.get_related_field().attname)} 255 else: 256 manager.core_filters = {'%s__pk' % rel_field.name: instance._get_pk_val()} 257 277 manager.core_filters = {'%s__pk' % rel_field.name: instance._get_pk_val()} 258 278 manager.model = self.related.model 259 279 … … 265 285 # multiple "remote" values and have a ManyToManyField defined in their 266 286 # model (rather than having another model pointed *at* them). 267 # In the example " poll.sites", the sites attribute is a287 # In the example "article.publications", the publications attribute is a 268 288 # ReverseManyRelatedObjectsDescriptor instance. 269 289 def __init__(self, m2m_field): … … 291 311 return superclass.get_query_set(self).filter(**(self.core_filters)) 292 312 293 def add(self, *objs , **kwargs):313 def add(self, *objs): 294 314 _add_m2m_items(self, superclass, rel_model, join_table, source_col_name, 295 target_col_name, instance._get_pk_val(), *objs , **kwargs)315 target_col_name, instance._get_pk_val(), *objs) 296 316 297 317 # If this is a symmetrical m2m relation to self, add the mirror entry in the m2m table 298 318 if instance.__class__ == rel_model and symmetrical: 299 319 _add_m2m_items(self, superclass, rel_model, join_table, target_col_name, 300 source_col_name, instance._get_pk_val(), *objs, **kwargs) 301 320 source_col_name, instance._get_pk_val(), *objs) 302 321 add.alters_data = True 303 322 … … 305 324 _remove_m2m_items(rel_model, join_table, source_col_name, 306 325 target_col_name, instance._get_pk_val(), *objs) 307 326 308 327 # If this is a symmetrical m2m relation to self, remove the mirror entry in the m2m table 309 328 if instance.__class__ == rel_model and symmetrical: 310 329 _remove_m2m_items(rel_model, join_table, target_col_name, 311 source_col_name, instance._get_pk_val(), *objs) 312 330 source_col_name, instance._get_pk_val(), *objs) 313 331 remove.alters_data = True 314 332 … … 319 337 if instance.__class__ == rel_model and symmetrical: 320 338 _clear_m2m_items(join_table, target_col_name, instance._get_pk_val()) 321 322 339 clear.alters_data = True 323 340 341 def create(self, **kwargs): 342 new_obj = self.model(**kwargs) 343 new_obj.save() 344 self.add(new_obj) 345 return new_obj 346 create.alters_data = True 347 324 348 manager = RelatedManager() 325 326 349 manager.core_filters = {'%s__pk' % self.field.related_query_name() : instance._get_pk_val()} 327 328 350 manager.model = rel_model 329 351 … … 417 439 418 440 def contribute_to_related_class(self, cls, related): 419 setattr(cls, related.get_accessor_name(), ManyRelatedObjectsDescriptor(related, 'o2m'))441 setattr(cls, related.get_accessor_name(), ForeignRelatedObjectsDescriptor(related)) 420 442 421 443 class OneToOneField(RelatedField, IntegerField): … … 558 580 if related.model != related.parent_model or not self.rel.symmetrical: 559 581 # Add the descriptor for the m2m relation 560 setattr(cls, related.get_accessor_name(), ManyRelatedObjectsDescriptor(related , 'm2m'))582 setattr(cls, related.get_accessor_name(), ManyRelatedObjectsDescriptor(related)) 561 583 562 584 self.rel.singular = self.rel.singular or self.rel.to._meta.object_name.lower() django/branches/magic-removal/django/db/models/manager.py
r2307 r2409 88 88 return self.get_query_set().values(*args, **kwargs) 89 89 90 #################91 # OTHER METHODS #92 #################93 94 def add(self, **kwargs):95 new_obj = self.model(**kwargs)96 new_obj.save()97 return new_obj98 add.alters_data = True99 100 90 class ManagerDescriptor(object): 101 91 # This class ensures managers aren't accessible via model instances. django/branches/magic-removal/tests/modeltests/many_to_many/models.py
r2366 r2409 55 55 56 56 # Add a Publication directly via publications.add by using keyword arguments. 57 >>> a2.publications.add(title='Highlights for Children')57 >>> new_publication = a2.publications.create(title='Highlights for Children') 58 58 59 59 # Article objects have access to their related Publication objects. … … 124 124 125 125 # Adding via the other end using keywords 126 >>> p2.article_set.add(headline='Oxygen-free diet works wonders')126 >>> new_article = p2.article_set.create(headline='Oxygen-free diet works wonders') 127 127 >>> p2.article_set.all() 128 128 [NASA finds intelligent life on Earth, Oxygen-free diet works wonders] django/branches/magic-removal/tests/modeltests/many_to_one/models.py
r2307 r2409 49 49 50 50 # Create an Article via the Reporter object. 51 >>> new_article = r.article_set. add(headline="John's second story", pub_date=datetime(2005, 7, 29))51 >>> new_article = r.article_set.create(headline="John's second story", pub_date=datetime(2005, 7, 29)) 52 52 >>> new_article 53 53 John's second story … … 55 55 1 56 56 57 >>> new_article2 = r2.article_set.add(headline="Paul's story", pub_date=datetime(2006, 1, 17)) 57 # Create a new article, and add it to the article set. 58 >>> new_article2 = Article(headline="Paul's story", pub_date=datetime(2006, 1, 17)) 59 >>> r.article_set.add(new_article2) 60 >>> new_article2.reporter.id 61 1 62 >>> r.article_set.all() 63 [This is a test, John's second story, Paul's story] 64 65 # Add the same article to a different article set - check that it moves. 66 >>> r2.article_set.add(new_article2) 58 67 >>> new_article2.reporter.id 59 68 2 69 >>> r.article_set.all() 70 [This is a test, John's second story] 71 >>> r2.article_set.all() 72 [Paul's story] 60 73 61 74 # Reporter objects have access to their related Article objects. django/branches/magic-removal/tests/modeltests/many_to_one_null/models.py
r2259 r2409 40 40 41 41 # Create an Article via the Reporter object. 42 >>> a2 = r.article_set. add(headline="Second")42 >>> a2 = r.article_set.create(headline="Second") 43 43 >>> a2 44 44 Second django/branches/magic-removal/tests/modeltests/mutually_referential/models.py
r2157 r2409 21 21 22 22 # Create some children 23 >>> c = q.child_set. add(name='Charles')24 >>> e = q.child_set. add(name='Edward')23 >>> c = q.child_set.create(name='Charles') 24 >>> e = q.child_set.create(name='Edward') 25 25 26 26 # Set the best child django/branches/magic-removal/tests/modeltests/one_to_one/models.py
r2241 r2409 86 86 87 87 # Add a Waiter to the Restaurant. 88 >>> w = r.waiter_set. add(name='Joe')88 >>> w = r.waiter_set.create(name='Joe') 89 89 >>> w.save() 90 90 >>> w
