加载包含自然键的Django Fixture



如何加载Django fixture,使通过自然键引用的模型不会与预先存在的记录冲突?

我试图加载这样一个fixture,但我从MySQL后端收到IntegrityErrors,抱怨Django试图插入重复的记录,这毫无意义。

正如我所理解的Django的自然关键特性,为了完全支持dumppdate和loaddata的使用,您需要在模型中定义一个natural_key方法,在模型的管理器中定义get_by_natural_key方法。

例如,我有两个模型:

class PersonManager(models.Manager):
    def get_by_natural_key(self, name):
        return self.get(name=name)
class Person(models.Model):
    objects = PersonManager()
    name = models.CharField(max_length=255, unique=True)
    def natural_key(self):
        return (self.name,)
class BookManager(models.Manager):
    def get_by_natural_key(self, title, *person_key):
        person = Person.objects.get_by_natural_key(*person_key)
        return self.get(title=title, person=person)
class Book(models.Model):
    objects = BookManager()
    author = models.ForeignKey(Person)
    title = models.CharField(max_length=255)
    def natural_key(self):
        return (self.title,) + self.author.natural_key()
    natural_key.dependencies = ['myapp.Person']

我的测试数据库已经包含一个样本Person和Book记录,我用它来生成fixture:

[
    {
        "pk": null, 
        "model": "myapp.person", 
        "fields": {
            "name": "bob"
        }
    }, 
    {
        "pk": null, 
        "model": "myapp.book", 
        "fields": {
            "author": [
                "bob"
            ], 
            "title": "bob's book", 
        }
    }
]

我希望能够将这个fixture加载到数据库的任何实例中,以重新创建记录,无论它们是否已经存在于数据库中。

然而,当我运行python manage.py loaddata myfixture.json时,我会得到错误:

IntegrityError: (1062, "Duplicate entry '1-1' for key 'myapp_person_name_uniq'")

为什么Django试图重新创建Person记录,而不是重用已经存在的记录?

发现该解决方案需要对Django的loaddata命令进行一个非常小的补丁。由于Django开发人员不太可能接受这样的补丁,我在我的Django管理相关增强包中分叉了它。

关键代码的更改(loaddatanaturally.py的第189-201行)只涉及调用get_natural_key(),以查找循环中迭代反序列化对象的任何现有pk。

实际上,loaddata不应该与数据库中的现有数据一起工作,它通常用于模型的初始加载。看看这个问题的另一种方法:用现有数据将数据导入Django模型?

最新更新