gpt4 book ai didi

django - 如何从 Django 迁移中发送信号?

转载 作者:行者123 更新时间:2023-12-03 02:59:38 27 4
gpt4 key购买 nike

我使用 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),
]

同时,我希望每个新用户都有一个 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)

但是:该信号仅在迁移之外起作用。原因是 apps.get_model("auth", "User")django.contrib.auth.models.User 非常不同,没有发送信号。如果我尝试像这样手动执行此操作,则会失败:

signals.post_save.send(django.contrib.auth.models.User, instance=julia, created=True)

这会失败,因为信号处理程序会尝试创建一个 UserDetails,并通过 O2O 指向历史 User:

ValueError: Cannot assign "<User: User object>": "UserDetails.user" must be a "User" instance.

真糟糕。

好的,我可以直接调用信号处理程序。但我必须在关键字参数中传递历史 UserDetails 类(以及它需要的其他历史类)。此外,具有 UserDetails 的应用程序不是进行此数据迁移的应用程序,因此这将是一种丑陋的依赖关系,很容易破坏,例如如果从 INSTALLED_APPS 中删除 UserDetails 应用。

那么,这只是我必须用丑陋的代码和 FixMe 注释来解决的当前限制吗?或者有没有办法从数据迁移中发送信号?

最佳答案

您不能(也不应该)执行此操作,因为执行迁移时,您的 UserDetails 可能与您编写此迁移时的情况完全不同。这就是 django(和 South)使用“卡住模型”的原因,它与您编写迁移时相同。

“不幸的是”,您必须在迁移中卡住信号代码,以保持编写迁移时的预期行为

一个简单的示例,用于理解为什么在迁移中不使用真实模型(或信号等)很重要:

今天,我可以得到这个:

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')

然后,我进行了数据迁移(称为“populate_users”),它创建了新用户,并强制在其中执行 add_user_details 。没关系:今天可以使用。

明天,我会修复 UserDetailsadd_user_details 内的 typo_fild -> typo_field。创建新的架构迁移以重命名数据库中的字段。

此时,我的迁移“populate_users”将会失败,因为当创建新用户时,它将尝试创建一个带有字段“typo_field”的新UserDetails “数据库中尚不存在:该字段只会在下次迁移时在数据库中重命名。

因此,如果我想保持随时可用的良好迁移,我必须在迁移中复制 add_user_details 的行为。 add_user_details 的卡住必须通过 apps.get_model("myapp", "UserDetails") 使用卡住的模型 UserDetails 并创建一个新的模型UserDetailstypo_fild 也被卡住。

关于django - 如何从 Django 迁移中发送信号?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26542617/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com