Clone this instance and return the new, cloned instance. ``overrides`` should be a dictionary of override values for fields on the cloned instance. M2M or reverse FK relations listed in ``cascade`` iterable will be cascade-cloned. By default, if not listed in
(self, cascade=None, overrides=None, user=None)
| 263 | return super(CDBaseModel, self).save(*args, **kwargs) |
| 264 | |
| 265 | def clone(self, cascade=None, overrides=None, user=None): |
| 266 | """ |
| 267 | Clone this instance and return the new, cloned instance. |
| 268 | ``overrides`` should be a dictionary of override values for fields on |
| 269 | the cloned instance. |
| 270 | M2M or reverse FK relations listed in ``cascade`` iterable will be |
| 271 | cascade-cloned. By default, if not listed in ``cascade``, m2m/reverse |
| 272 | FKs will effectively be cleared (as the remote object will still be |
| 273 | pointing to the original instance, not the cloned one.) |
| 274 | If ``cascade`` is a dictionary, keys are m2m/reverse-FK accessor names, |
| 275 | and values are a callable that takes the queryset of all related |
| 276 | objects and returns those that should be cloned. |
| 277 | """ |
| 278 | if cascade is None: |
| 279 | cascade = {} |
| 280 | else: |
| 281 | try: |
| 282 | cascade.items |
| 283 | except AttributeError: |
| 284 | cascade = dict((i, lambda qs: qs) for i in cascade) |
| 285 | |
| 286 | if overrides is None: |
| 287 | overrides = {} |
| 288 | |
| 289 | overrides["created_time"] = utcnow() |
| 290 | overrides["creator"] = user |
| 291 | overrides["modifier"] = user |
| 292 | |
| 293 | clone = self.__class__() |
| 294 | |
| 295 | for field in self._meta.fields: |
| 296 | if field.primary_key: |
| 297 | continue |
| 298 | val = overrides.get(field.name, getattr(self, field.name)) |
| 299 | setattr(clone, field.name, val) |
| 300 | |
| 301 | clone.save(force_insert=True) |
| 302 | |
| 303 | for name, filter_func in cascade.items(): |
| 304 | mgr = getattr(self, name) |
| 305 | if mgr.__class__.__name__ == "ManyRelatedManager": # M2M |
| 306 | clone_mgr = getattr(clone, name) |
| 307 | existing = set(clone_mgr.all()) |
| 308 | new = set(filter_func(mgr.all())) |
| 309 | clone_mgr.add(*new.difference(existing)) |
| 310 | clone_mgr.remove(*existing.difference(new)) |
| 311 | elif mgr.__class__.__name__ == "RelatedManager": # reverse FK |
| 312 | reverse_name = getattr(self.__class__, name).related.field.name |
| 313 | for obj in filter_func(mgr.all()): |
| 314 | obj.clone(overrides={reverse_name: clone}) |
| 315 | else: |
| 316 | raise ValueError( |
| 317 | "Cannot cascade-clone '{0}'; " |
| 318 | "not a many-to-many or reverse foreignkey.".format(name)) |
| 319 | |
| 320 | return clone |
| 321 | |
| 322 | def delete(self, user=None, permanent=False): |