Django - 如何复制使用带有直通模型的m2m字段的模型实例

时间:2014-04-16 18:50:19

标签: django django-models django-admin

我正在尝试编写管理操作来复制下面的Circus模型。

到目前为止,我的代码存在的问题是,当我尝试运行它时,我收到类似的错误:

  

无法在指定中介的ManyToManyField上设置值   模型。

以下是我的模特:

class Clown(models.Model):
    name = models.CharField(max_length=255)

class Circus(models.Model):
    clowns = models.ManyToManyField(Clown, blank=True, through='WorkedAt')
    name = models.CharField(max_length=255)

class WorkedAt(models.Model):
    clown = models.ForeignKey(Clown)
    circus = models.ForeignKey(Circus)

以下是admin.py中的代码:(尝试关注the advice here

class CircusAdmin(BaseAdmin):
    def duplicate(self, request, queryset):
        for obj in queryset:
            old_clowns = obj.clowns.all()
            obj.id = None
            obj.name += ' (copy)'
            obj.save()
            obj.clowns = old_clowns
    duplicate.short_description = "Duplicate Selected Circuses"
    actions = [duplicate]

1 个答案:

答案 0 :(得分:3)

当您使用中间through表时,您使用相关对象管理器(即obj.clowns)的能力是有限的。正如docs所说:

  

与普通的多对多字段不同,您不能使用添加,创建或分配(即beatles.members = [...])来创建关系....简单的添加,创建和分配调用不提供指定此额外细节的方法。因此,对于使用中间模型的多对多关系,它们被禁用。创建此类关系的唯一方法是创建中间模型的实例。

因此,不是分配相关的经理,而是自己创建新的中间对象:

def duplicate(self, request, queryset): 
    for obj in queryset: 
        old_workedat = list(obj.workedat_set.all())

        obj.id = None 
        obj.name += ' (copy)' 
        obj.save() 

        new_workedat = [WorkedAt(circus_id=obj.id, clown_id=wa.clown_id)
                        for wa in old_workedat]
        WorkedAt.objects.bulk_create(new_workedat)