我已经为模型Books,Chapters和Pages。它们全部由编写User:
Books,Chapters
Pages
from django.db import models class Book(models.Model) author = models.ForeignKey('auth.User') class Chapter(models.Model) author = models.ForeignKey('auth.User') book = models.ForeignKey(Book) class Page(models.Model) author = models.ForeignKey('auth.User') book = models.ForeignKey(Book) chapter = models.ForeignKey(Chapter)
我想做的就是复制一个现有的Book并更新User给其他人。皱纹是我也想复制所有相关模型实例的Book-它所有的Chapters和Pages以及!
Book
Chapters
观察时,事情变得非常棘手Page-不仅Pages需要author更新其字段,而且还需要指向新Chapter对象!
Page-
author
Chapter
Django是否支持开箱即用的方式?用于复制模型的通用算法是什么样的?
由于删除了CollectedObjects,因此它在Django 1.3中不再起作用。参见变更集14507
我在Django片段上发布了我的解决方案。它很大程度上取决于django.db.models.query.CollectedObject用于删除对象的代码:
django.db.models.query.CollectedObject
from django.db.models.query import CollectedObjects from django.db.models.fields.related import ForeignKey def duplicate(obj, value, field): """ Duplicate all related objects of `obj` setting `field` to `value`. If one of the duplicate objects has an FK to another duplicate object update that as well. Return the duplicate copy of `obj`. """ collected_objs = CollectedObjects() obj._collect_sub_objects(collected_objs) related_models = collected_objs.keys() root_obj = None # Traverse the related models in reverse deletion order. for model in reversed(related_models): # Find all FKs on `model` that point to a `related_model`. fks = [] for f in model._meta.fields: if isinstance(f, ForeignKey) and f.rel.to in related_models: fks.append(f) # Replace each `sub_obj` with a duplicate. sub_obj = collected_objs[model] for pk_val, obj in sub_obj.iteritems(): for fk in fks: fk_value = getattr(obj, "%s_id" % fk.name) # If this FK has been duplicated then point to the duplicate. if fk_value in collected_objs[fk.rel.to]: dupe_obj = collected_objs[fk.rel.to][fk_value] setattr(obj, fk.name, dupe_obj) # Duplicate the object and save it. obj.id = None setattr(obj, field, value) obj.save() if root_obj is None: root_obj = obj return root_obj