合并模型,Django 1.11

Merging models, Django 1.11

从 Django 1.8 升级到 1.11 后,我一直在寻找一种合并一些记录的方法 - 例如,某些模型有多个具有相同 name 字段的条目。这里有一个答案似乎有我需要的东西:

我用这样的模型试过:

class GeneralType(models.Model):
    #...
    domains = models.ManyToManyField(Domain, blank=True)
    #...

class Domain(models.Model):
    name = models.TextField(blank=False)
    #...

...其中 Domain 有各种重名的记录。但是,它在指定的位置失败了:

def merge(primary_object, alias_objects=list(), keep_old=False):
    """
    Use this function to merge model objects (i.e. Users, Organizations, Polls,
    etc.) and migrate all of the related fields from the alias objects to the
    primary object.  This does not look at GenericForeignKeys.

    Usage:
    from django.contrib.auth.models import User
    primary_user = User.objects.get(email='good_email@example.com')
    duplicate_user = User.objects.get(email='good_email+duplicate@example.com')
    merge(primary_user, duplicate_user)
    """

    # ...snip....

    for alias_object in alias_objects:
        for related_object in alias_object._meta.related_objects:
            related_name = related_object.get_accessor_name()
            if related_object.field.many_to_one:
                #...snip...
            elif related_object.field.one_to_one:
                #...snip...
            elif related_object.field.many_to_many:
                related_name = related_name or related_object.field.name
                for obj in getattr(alias_object, related_name).all():
                    getattr(obj, related_name).remove(alias_object) # <- fails here
                    getattr(obj, related_name).add(primary_object)

问题显然是'GeneralType' object has no attribute 'generaltype_set'。将 related_name 添加到 GeneralType 并不能解决这个问题——脚本以同样的方式失败,但引用了我现在给它的名称。我不太确定 Django 在这里做什么,所以欢迎任何建议。

编辑:

在 Django 中 shell 我可以成功地从 Domain 引用 GeneralType,所以我没有得到上面的脚本。示例:

>>> d = Domain.objects.first()
>>> d
<Domain: 16s RNA>
>>> d.generaltype_set  
<django.db.models.fields.related_descriptors.ManyRelatedManager object at 0x11175ba90>
>>> d.generaltype_set.first()
<GeneralType: Greengenes>
>>> getattr(d,'generaltype_set')
<django.db.models.fields.related_descriptors.ManyRelatedManager object at 0x10aa38250>

我想出了一个解决方法。如果我在脚本的 getattr(obj, related_name) 部分引用 generaltype.domains 似乎一切都会起作用,所以我在上面的问题中标记为失败的行之前如下修改它:

if obj.__class__.__name__ == 'GeneralType':
    related_name = 'domains'

一切运行 似乎在那之后。