在Django中复制模型实例及其相关对象/用于可复制对象的算法

我已经为模型Books,ChaptersPages。它们全部由编写User:

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-它所有的ChaptersPages以及!

观察时,事情变得非常棘手Page-不仅Pages需要author更新其字段,而且还需要指向新Chapter对象!

Django是否支持开箱即用的方式?用于复制模型的通用算法是什么样的?

回答:

由于删除了CollectedObjects,因此它在Django 1.3中不再起作用。参见变更集14507

我在Django片段上发布了我的解决方案。它很大程度上取决于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

以上是 在Django中复制模型实例及其相关对象/用于可复制对象的算法 的全部内容, 来源链接: utcz.com/qa/401413.html

回到顶部