Bry*_*yce 17 django django-models django-south
我有一个模特
class Category(models.Model):
title = models.CharField(...)
entry = models.ManyToManyField(Entry,null=True,blank=True,
related_name='category_entries',
)
Run Code Online (Sandbox Code Playgroud)
我希望重构每个关系的附加数据:
class Category(models.Model):
title = models.CharField(...)
entry = models.ManyToManyField(Entry,null=True,blank=True,
related_name='category_entries',
through='CategoryEntry',
)
Run Code Online (Sandbox Code Playgroud)
但是南方删除了现有的表格.我如何保留现有的mtm关系?
ygr*_*ram 27
在Django 1.7+内置迁移中,计算"代码状态"(即模型的代码定义)的方式是不同的,并且需要不同的解决方案.
在South(Django pre-1.7)中,整个"代码状态"保存在每次迁移中 - 但是在Django 1.7+内置迁移中,它是从查看整个迁移集中得出的,因此您需要指定"代码"陈述"在不改变数据库的情况下改变迁移.
如上所述,这需要在几个步骤中完成.
创建一个中间模型,如上面的答案:
class CategoryEntry(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE)
entry = models.ForeignKey(Entry, on_delete=models.CASCADE)
class Meta:
db_table = 'main_category_entries' #change main_ to your application
unique_together = ('category', 'entry')
Run Code Online (Sandbox Code Playgroud)使用django-admin.py makemigrations和修改代码创建自动迁移; 将操作列表移动到操作的state_operations参数中migrations.SeparateDatabaseAndState,并将database_operations列表保留为空.它应该看起来像:
class Migration(migrations.Migration):
operations = [
migrations.SeparateDatabaseAndState(
state_operations=[
migrations.CreateModel(CategoryEntry..)
...
],
database_operations=[]
),
]
Run Code Online (Sandbox Code Playgroud)编辑CategoryEntry以包含您想要的内容并使用创建新的自动迁移django-admin.py makemigrations
gre*_*reg 21
暂时创建没有任何额外字段的中间模型.为它提供一个唯一约束来匹配现有约束,并指定表名以匹配现有名称:
class CategoryEntry(models.Model):
category = models.ForeignKey(Category)
entry = models.ForeignKey(Entry)
class Meta:
db_table='main_category_entries' #change main_ to your application
unique_together = (('category', 'entry'))
Run Code Online (Sandbox Code Playgroud)运行南模式迁移.
编辑生成的模式迁移脚本并注释掉所有前向和后向条目,因为您将重新使用现有的交集表.添加pass完成方法.
运行迁移.
更新任何现有代码.正如在https://docs.djangoproject.com/en/dev/topics/db/models/#many-to-many-relationships中所说,"与普通的多对多字段不同,你不能使用add,创建或分配以创建关系"因此您需要修改任何现有的应用程序代码,例如
c.entry.add(e)
Run Code Online (Sandbox Code Playgroud)
可能成为:
try:
categoryentry = c.categoryentry_set.get(entry = e)
except CategoryEntry.DoesNotExist:
categoryentry = CategoryEntry(category=c, entry=e)
categoryentry.save()
Run Code Online (Sandbox Code Playgroud)
和:
e.category_entries.add(c)
Run Code Online (Sandbox Code Playgroud)
可能成为:
categoryentry = CategoryEntry(category=c, entry=e) #set extra fields here
categoryentry.save()
Run Code Online (Sandbox Code Playgroud)
和:
c.entry.remove(e)
Run Code Online (Sandbox Code Playgroud)
可能成为:
categoryentry = c.categoryentry_set.get(entry = e)
categoryentry.delete()
Run Code Online (Sandbox Code Playgroud)完成此初始伪迁移后,您应该能够将额外字段添加到其中CategoryEntry并正常创建进一步的迁移.
Django 文档将这种确切的情况作为migrations.SeparateDatabaseAndState 操作的应用程序。我完全按照文档所述进行操作,但 Django 不断抛出异常,指出用于 M2M 映射的表不存在。
我通过中间模型的 Meta 类的“db_table”属性分配一个表名,这导致了问题(不知道为什么)。然后我明白了,Django文档中的示例中显示的SQL代码是将Django为标准M2M关系中的M2M关系表分配的名称更改为Django为所使用的中介模型对应的表分配的新名称。
database_operations=[
# Old table name from checking with sqlmigrate, new table
# name from AuthorBook._meta.db_table.
migrations.RunSQL(
sql='ALTER TABLE core_book_authors RENAME TO core_authorbook',
reverse_sql='ALTER TABLE core_authorbook RENAME TO core_book_authors',
),
],
Run Code Online (Sandbox Code Playgroud)
在此示例中,“core_book_authors”是M2M关系表的旧名称,“core_authorbook”是M2M关系表的新名称。如果您不在迁移中包含此代码,您将无法向中间模型添加额外的字段(我认为这是拥有自定义 M2M 关系的主要原因),因为 Django 将查找新的表名称。
总结一下我使用“through”将标准 M2M 关系更改为自定义关系所做的工作:
py manage.py makemigrations。我将此自动生成的迁移更改为类似于上面引用的文档中的迁移。py manage.py migrate。py manage.py makemigrations。py manage.py migrate。之前表示标准 M2M 关系的表现在将具有不同的名称和所有新列。如果表中已有数据,那么这些列具有默认值非常重要。我发现这是最直接的方法,不会丢失任何数据。
| 归档时间: |
|
| 查看次数: |
4894 次 |
| 最近记录: |