Tor*_*ger 11 django data-migration django-signals django-migrations
我使用Django 1.7迁移,特别是想要用初始数据填充新创建的数据库.因此,我使用数据迁移.它看起来像这样:
def populate_with_initial_data(apps, schema_editor):
User = apps.get_model("auth", "User")
new_user = User.objects.create(username="nobody")
class Migration(migrations.Migration):
...
operations = [
migrations.RunPython(populate_with_initial_data),
]
Run Code Online (Sandbox Code Playgroud)
同时,我希望UserDetails
每个新用户都有一个模型实例:
@receiver(signals.post_save, sender=django.contrib.auth.models.User)
def add_user_details(sender, instance, created, **kwargs):
if created:
my_app.UserDetails.objects.create(user=instance)
Run Code Online (Sandbox Code Playgroud)
但是:此信号仅在迁移之外有效.原因是,apps.get_model("auth", "User")
与django.contrib.auth.models.User
没有发送信号的情况完全不同.如果我尝试手动执行此操作,则会失败:
signals.post_save.send(django.contrib.auth.models.User, instance=julia, created=True)
Run Code Online (Sandbox Code Playgroud)
这失败了,因为那时,信号处理程序尝试使用O2O 创建一个新的 UserDetails
指向历史记录 User
:
ValueError: Cannot assign "<User: User object>": "UserDetails.user" must be a "User" instance.
Run Code Online (Sandbox Code Playgroud)
游民.
好的,我可以直接调用信号处理程序.但是我必须UserDetails
在关键字参数(以及它需要的其他历史类)中传递历史类.此外,UserDetails
具有此数据迁移的应用程序不是具有此数据迁移的应用程序,因此这将是一个丑陋的依赖性,很容易破坏,例如,如果UserDetails
应用程序被删除INSTALLED_APPS
.
那么,这只是一个当前的限制,我必须解决丑陋的代码和FixMe评论?或者有没有办法从数据迁移中发送信号?
您不能(也不应该)这样做,因为在执行迁移时,您UserDetails
可能与编写此迁移时的情况完全不同.这就是为什么django(和南方)使用与你编写迁移时相同的"冻结模型"的原因.
"不幸的是",您必须在迁移中冻结信号代码,以保持编写迁移时的预期行为.
一个简单的例子,可以理解为什么在迁移中不使用真实模型(或信号等)很重要:
今天,我可以这样:
class UserDetails(models.Model):
user = models.ForeignKey(...)
typo_fild = models.CharField(...)
@receiver(signals.post_save, sender=django.contrib.auth.models.User)
def add_user_details(sender, instance, created, **kwargs):
if created:
UserDetails.objects.create(user=instance, typo_fild='yo')
Run Code Online (Sandbox Code Playgroud)
然后,我有一个数据迁移(称为"populate_users"),它创建新用户,并强制执行add_user_details
它.没关系:它今天有效.
明天,我修复了我的typo_fild
- > typo_field
内部UserDetails
和内部add_user_details
.创建新的模式迁移以重命名数据库中的字段.
此时,我的迁移"populate_users" 将失败,因为当创建一个新用户时,它将尝试创建一个新UserDetails
的字段"typo_field",该字段在数据库中尚不存在:此字段只会在DB具有下一次迁移.
所以,如果我希望保持良好的迁移能够随时工作,我必须复制add_user_details
迁移内部的行为.这一冻结add_user_details
将不得不使用冷冻模型UserDetails
通过apps.get_model("myapp", "UserDetails")
创建一个新的UserDetails
与typo_fild
它太冻结.
归档时间: |
|
查看次数: |
2246 次 |
最近记录: |