Django中模型实例及其相关对象的复制/重复复制对象的算法

2024-04-20 06:24:19 发布

您现在位置:Python中文网/ 问答频道 /正文

我有BooksChaptersPages的模型。它们都是由一个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是否支持这种开箱即用的方式?复制模型的通用算法是什么样子的?

干杯

约翰


更新:

上面给出的类只是一个例子来说明我遇到的问题!


Tags: 模型authmodelmodelspagepagesbooksclass
3条回答

这在Django 1.3中不再有效,因为CollectedObjects被删除了。见changeset 14507

I posted my solution on Django Snippets.它主要基于用于删除对象的^{}代码:

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中尝试过,但python的deepcopy可能只对您有用

编辑:

如果实现以下函数,则可以定义模型的自定义复制行为:

__copy__() and __deepcopy__()

这里有一个简单的方法来复制你的对象。

基本上:

(1)将原始对象的id设置为“无”:

book_to_copy.id=无

(2)更改“author”属性并保存ojbect:

book_to_copy.author=新作者

预订到副本。保存()

(3)执行插入而不是更新

(这并不是要改变页面中的作者——我同意关于重新构建模型的评论)

相关问题 更多 >