Python Django模型继承:创建现有实例的子实例(向下转换)?
我正在尝试集成一个第三方Django应用程序,该应用程序做出了从Python Django模型继承:创建现有实例的子实例(向下转换)?,python,django,inheritance,Python,Django,Inheritance,我正在尝试集成一个第三方Django应用程序,该应用程序做出了从Django.contrib.auth.models.User继承的不幸决定,这对于可插拔应用程序来说是一个很大的禁忌。引述: 不过,更重要的是,正如在Python中一样,您不能使用 Django的模型继承。也就是说,如果您已经创建了用户 比如说,如果你不在被子底下翻来覆去的话,你就无法做到这一点 实例对应于尚未创建的子类实例 嗯,我现在的情况是,我需要将这个第三方应用程序与我现有的用户实例集成。那么,如果假设我真的愿意在被子底下翻
Django.contrib.auth.models.User
继承的不幸决定,这对于可插拔应用程序来说是一个很大的禁忌。引述:
不过,更重要的是,正如在Python中一样,您不能使用
Django的模型继承。也就是说,如果您已经创建了用户
比如说,如果你不在被子底下翻来覆去的话,你就无法做到这一点
实例对应于尚未创建的子类实例
嗯,我现在的情况是,我需要将这个第三方应用程序与我现有的用户实例集成。那么,如果假设我真的愿意在被子底下翻来覆去,我有什么选择呢?我知道这是行不通的:
extended_user = ExtendedUser(user_ptr_id=auth_user.pk)
extended_user.save()
没有例外,但它会破坏所有类型的内容,首先用空字符串覆盖django.contrib.auth.models.User
中的所有列…这应该可以:
extended_user = ExtendedUser(user_ptr_id=auth_user.pk)
extended_user.__dict__.update(auth_user.__dict__)
extended_user.save()
在这里,您基本上只是将auth_用户版本中的值复制到extended_用户版本中,然后重新保存它。不是很优雅,但它可以工作。如果您不喜欢
\uu dict\uuuuu。更新解决方案,您可以执行以下操作:
for field in parent_obj._meta.fields
setattr(child_obj, field.attname, getattr(parent_obj, field.attname))
我使用的是Django 1.6,我的ExtendedUser
模型来自OSQA(forum.models.user.user
)。出于某种奇怪的原因,上述使用指令的解决方案和使用setattr
的解决方案有时会失败。这可能与我拥有的其他一些模型有关,这些模型在用户表上设置了约束。您还可以尝试以下两种变通方法:
解决办法#1:
解决办法#2:
也就是说,如果同时设置pk
和id
,有时保存新的子实例会失败,但您可以只设置pk
,保存它,然后一切似乎都正常工作。我通过询问django用户邮件列表找到了这个答案:
这不是公共API的一部分,但您可以依赖Django如何在内部加载fixture
parent = Restaurant.objects.get(name__iexact="Bob's Place").parent
bar = Bar(parent=parent, happy_hour=True)
bar.save_base(raw=True)
请记住,这可能会与Django的任何新版本决裂。这样的东西怎么样:
from django.forms.models import model_to_dict
auth_user_dict = model_to_dict(auth_user)
extended_user = ExtendedUser.objects.create(user_ptr=auth_user, **auth_user_dict)
对于这个问题,有一个公开的bug:
建议的修补程序()未使用obj.\uuu dict\uuu
但是创建一个字典,其中所有字段值在所有字段上循环。
这里有一个简化的函数:
def create_child_from_parent_model(child_cls, parent_obj, init_values: dict):
attrs = {}
for field in parent_obj._meta._get_fields(reverse=False, include_parents=True):
if field.attname not in attrs:
attrs[field.attname] = getattr(parent_obj, field.attname)
attrs[child_cls._meta.parents[parent_obj.__class__].name] = parent_obj
attrs.update(init_values)
print(attrs)
return child_cls(**attrs)
create_child_from_parent_model(ExtendedUser, auth_user, {})
此方法的优点是,被子方法覆盖的方法不会被原始父方法替换。
对于我来说,使用原始答案obj.\uu dict\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
parent_object = parent_model.objects.get(pk=parent_id)
new_child_object_with_existing_parent = Child(parent_ptr=parent, child_filed1='Nothing')
new_child_object_with_existing_parent.save()
我想在我的个人资料模型中为现有用户创建条目,我的模型如下
from django.contrib.auth.models import User as user_model
class Profile(user_model):
bio = models.CharField(maxlength=1000)
another_filed = models.CharField(maxlength=1000, null=True, blank=True)
在某个地方,如果现有用户不存在配置文件,我需要创建配置文件,所以我像下面这样做
对我有用的例子
from meetings.user import Profile
from django.contrib.auth.models import User as user_model
user_object = user_model.objects.get(pk=3)
profile_object = Profile(user_ptr=user_object, bio='some')
profile_object.save()
太好了,谢谢你,丹尼尔。让我摆脱了这个困境:。在保存之前,您应该从dict中排除pk或将其重置为无。另见另一个答案。否则你只是在等待一个完整的错误。男人终于解决了。在这个问题上耽搁太久了。谢谢有人知道如何在不重新保存/更新所有字段的情况下执行此操作吗??我试图在保存中指定select update_字段,但无法确定需要什么。我尝试过(pk、id、user_ptr_id和parent)和一些更牵强的方法,但都不管用!这给了我一个错误“无法设置属性”当通过管理操作使用时。这似乎适用于除许多字段之外的所有字段,不幸的是这对我来说是一个问题。如果是这样的话,你知道怎么办吗?
from django.contrib.auth.models import User as user_model
class Profile(user_model):
bio = models.CharField(maxlength=1000)
another_filed = models.CharField(maxlength=1000, null=True, blank=True)
from meetings.user import Profile
from django.contrib.auth.models import User as user_model
user_object = user_model.objects.get(pk=3)
profile_object = Profile(user_ptr=user_object, bio='some')
profile_object.save()