我有一个名为Document
的模型,我想添加一个位于其上方的新表DocumentCluster
,并带有Document
的外键。
class DocumentCluster(models.Model):
sub_document = models.ForeignKey(Document)
...lots of fields here...
当我使用South添加此表时,我需要通过将主键和外键设置为相同的值来填充它。
例如,如果我当前有一个Document
对象,pk
为12,则新DocumentCluster
对象的pk
为12,外键为Document
号码12。
虽然我们需要DocumentCluster
pk
值来匹配外键值似乎很奇怪,但有一个重要原因。我们在网址中使用了Document
pk
,但在更改后,网址将加载DocumentCluster
,而不是Document
,因此我们需要pk
} DocumentCluster
中的内容与Document
中的相同。
完成后,我希望DocumentCluster
的PK为自动字段,从已迁移的最高值开始递增。
可以这样做吗?
答案 0 :(得分:1)
你不能从 DocumentCluster.pk
到 Document
拥有FK ,同时让DocumentCluster.pk
成为{{3} }列。这是一个矛盾。它必须是两个单独的列。我想你的意思是反过来: 从 Document
到 DocumentCluster
。
这可以使用SQL DDL命令完成:
BEGIN;
CREATE TABLE DocumentCluster (pk serial, lots text, of_fields int, ...);
INSERT INTO DocumentCluster (pk, lots, of_fields, ...)
SELECT pk, lots, of_fields, ... FROM Document
ORDER BY pk; -- optional
ALTER TABLE DocumentCluster ADD CONSTRAINT DocumentCluster_pkey
PRIMARY KEY (pk); -- could be integrated in CREATE TABLE
ALTER TABLE Document -- and not the other way round!
ADD CONSTRAINT pk_fk FOREIGN KEY (pk) REFERENCES DocumentCluster(pk);
SELECT setval(pg_get_serial_sequence('DocumentCluster', 'pk'), max(pk))
FROM DocumentCluster; -- update SEQUENCE to highest value
COMMIT;
您的混淆图层(Django)可能使用双引号名称,例如"Document"
,在这种情况下您必须执行相同的操作...
PK可以在CREATE TABLE
语句中声明,但在插入行后添加它会更便宜 - 假设pk
为unique not null
。
更多解释和链接:
答案 1 :(得分:1)
使用南方这比我想象的要简单得多。
像往常一样使用south schemamigration 命令来构建添加DocumentCluster模型的架构迁移。
然后使用 datamigration 命令为下一次迁移构建骨架:
./manage.py datamigration yourapp populate_clusters
然后在生成的python迁移文件中填写 forwards 方法,如下所示:
def forwards(self, orm):
max_id = -1
clusters_added = 0
for document in orm.Document.objects.all():
cluster = orm.DocumentCluster()
cluster.id = document.id
cluster.sub_document = document
cluster.save()
max_id = max(max_id, document.id)
clusters_added +=1
if max_id >= clusters_added:
orm.DocumentCluster.objects.raw("SELECT "\
"setval(pg_get_serial_sequence('yourapp_documentcluster',"\
"'id'), %d)" % max_id+1)
(此数据迁移中的 reverse 方法只会删除所有DocumentModel实例。)
如果这个' populate_clusters'迁移步骤在添加DocumentCluster表的迁移步骤之后立即运行,然后DocumentCluster表为空,并且serial / autokey计数器从零开始。如果您从未删除任何文档,则序列/自动键计数器值将以 Document pk值的下一个未使用值结束,您甚至不必碰撞如Erwin的答案所示。
但是,如果您删除了文档实例,或者如果某个 id 值被跳过,那么您需要使用这个序列/自动键计数器来提升SQL。 Django提供了一种直接执行原始SQL的方法。 (我不认为你可以不使用原始SQL)。
为安全起见,您应该检查cluster.id是否是< =循环中看到的最大document.id值。