Django & South:在数据迁移中执行 obj.save() 时不执行自定义字段方法。



在我的Django模型中,我有两个字段,name(一个常规的CharField)和slug,这是一个自定义字段,根据字段定义中传递的字段名生成段塞,在这种情况下,我使用name

首先,该模型只有name字段,以及相应的迁移等等。然后我需要添加slug字段,所以按照South的约定,我用unique=False添加了slug字段,创建了模式迁移,然后创建了数据迁移,设置了unique=True,并为最后的更改创建了另一个迁移。

由于slug的值是在模型保存时生成的,所以在数据迁移的forwards方法中,我所做的是迭代orm['myapp.MyModel'].objects.all()返回的查询集,并在每个实例上调用save()方法。

但是,段塞场的值永远不会生成。在一个IPython会话下,我做了同样的事情,但将模型引用为from myapp.models import MyModel,并成功了。使用一些调试语句,打印South的orm dict返回的模型的type显示了真实的类,它似乎不是South动态构建的伪模型。

当使用pre_save方法时,段塞字段会创建它的值。如何在数据迁移过程中强制调用它?我需要确保值的唯一性,以便在以后的架构迁移中应用索引时,列不会包含重复的值。

谢谢!

顺便说一句:slug字段类确实定义了south_field_triple,所以South玩得很好。

编辑:请看我的答案。但更像是一个答案,感觉更像是黑客。有更好/正确的方法吗?

通常,您应该在迁移中尽可能紧密地显式复制生成字段内容的代码(这是一个罕见的有目的的代码复制示例)。方法中的代码,即使有效,也会调用执行迁移时定义的pre_save,这可能与创建迁移时的模型状态发生了变化,甚至失败(这可能取决于以前不存在的其他字段等)

因此,在您的示例中,正确的方法是直接使用slugify(),就像在SlugField的pre_save方法中所做的那样:

from django.template.defaultfilters import slugify
class Migration(DataMigration):
    def forwards(self, orm):
        "Write your forwards methods here."
        for myobj in orm['myapp.MyModel'].objects.all():
            myobj.slug = slugify(myobj.otherfield)
            myobj.save()

我通过获得模型字段实例并直接调用它的pre_save来暂时解决这个问题:

class Migration(DataMigration):
    def forwards(self, orm):
        "Write your forwards methods here."
        # Note: Remember to use orm['appname.ModelName'] rather than "from appname.models..."
        for myobj in orm['myapp.MyModel'].objects.all():
            slug_field = myobj._meta.get_field_by_name('slug')[0]
            myobj.slug = slug_field.pre_save(myobj, add=False)
            myobj.save()

然而,在自定义字段中考虑这一点会让人觉得很麻烦。。。

最新更新