Django模型继承:如何创建现有实例的子实例(向下转型)?

55 投票
7 回答
12943 浏览
提问于 2025-04-16 06:21

我正在尝试把一个第三方的Django应用整合进我的项目,但这个应用做了一个不太聪明的决定,它直接继承了django.contrib.auth.models.User,这在可插拔的应用中是个大忌。引用一下Malcolm Tredinnick的话:

更重要的是,就像在Python中一样,你不能在Django的模型继承中进行“向下转型”。也就是说,如果你已经创建了一个用户实例,你不能在不深入研究底层代码的情况下,让这个实例对应一个你还没有创建的子类实例。

现在我面临的情况是,我需要把这个第三方应用和我现有的用户实例整合在一起。所以,假设我真的愿意深入研究底层代码,我有哪些选择呢?我知道这样做是行不通的:

extended_user = ExtendedUser(user_ptr_id=auth_user.pk)
extended_user.save()

虽然没有报错,但会导致各种问题,首先是把django.contrib.auth.models.User中的所有字段都覆盖成空字符串……

7 个回答

6

如果你不喜欢用 __dict__.update 这个方法,你可以试试这样做:

for field in parent_obj._meta.fields
    setattr(child_obj, field.attname, getattr(parent_obj, field.attname))
8

我在django-user邮件列表上提问时找到了这个答案:

https://groups.google.com/d/msg/django-users/02t83cuEbeg/JnPkriW-omQJ

这不是公开的API的一部分,但你可以依赖Django内部加载数据的方式。

parent = Restaurant.objects.get(name__iexact="Bob's Place").parent
bar = Bar(parent=parent, happy_hour=True)
bar.save_base(raw=True)

请记住,这个方法在Django的任何新版本中可能会失效。

76

这个方法应该可以用:

extended_user = ExtendedUser(user_ptr_id=auth_user.pk)
extended_user.__dict__.update(auth_user.__dict__)
extended_user.save()

在这里,你基本上就是把auth_user里的值复制到extended_user里,然后再保存。虽然这个方法不是特别优雅,但确实能解决问题。

撰写回答