代码之家  ›  专栏  ›  技术社区  ›  Benjamin Wohlwend

Django模型继承:创建现有实例(下拉)的子实例?

  •  45
  • Benjamin Wohlwend  · 技术社区  · 14 年前

    我正在尝试集成一个第三方Django应用程序,它做出了一个不幸的决定,从 django.contrib.auth.models.User Malcolm Tredinnick :

    不过,更重要的是,正如在Python中一样,不能用 Django的模型继承。也就是说,如果您已经创建了用户 例如,如果你不在被子底下翻来翻去,你就不可能做到

    我现在需要把这个第三方应用程序与我现有的用户实例集成在一起。所以,如果假设我真的愿意在幕后指手画脚,我有什么选择?我知道这不管用:

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

    没有例外,但它会破坏所有类型的内容,从覆盖 空字符串。。。

    7 回复  |  直到 9 年前
        1
  •  66
  •   Daniel Roseman    14 年前

    这应该有效:

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

    在这里,您只需将auth_user版本中的值复制到extended_user版本中,然后重新保存它。不是很优雅,但很管用。

        2
  •  6
  •   podshumok    11 年前

    __dict__.update 解决方案您可以这样做:

    for field in parent_obj._meta.fields
        setattr(child_obj, field.attname, getattr(parent_obj, field.attname))
    
        3
  •  5
  •   guettli    9 年前

    我在django用户邮件列表中找到了这个答案:

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

    这不是公共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)
    

        4
  •  2
  •   Sergey Orshanskiy    10 年前

    我用的是Django 1.6 ExtendedUser 型号来自OSQA( forum.models.user.User dict.__update__ setattr 有时会失败。这可能与我拥有的其他一些模型有关,这些模型正在对用户表施加约束。以下是另外两个解决方法,您可以尝试:

    extended_user = ExtendedUser(user_ptr_id = user.pk)
    extended_user.save() # save first time
    extended_user.__dict__.update(user.__dict__)
    extended_user.save() # save second time
    

    解决方法2:

    extended_user = ExtendedUser(user_ptr_id = user.pk)
    extended_user.__dict__.update(user.__dict__)
    extended_user.id=None
    extended_user.save()
    

    pk id ,但你可以设置 ,保存它,然后一切看起来都很好。

        5
  •  1
  •   Kound    5 年前

    这个问题有一个开放的bug: https://code.djangoproject.com/ticket/7623

    建议的修补程序( https://github.com/django/django/compare/master...ar45:child_object_from_parent_model obj.__dict__ 但是创建一个字典,所有字段值在所有字段上循环。 这里有一个简化的函数:

    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.__dict__.update() FieldTracker model_utils

        6
  •  0
  •   Braden Holt    6 年前

    像这样的事情呢:

    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)
    
        7
  •  -1
  •   Sami    5 年前

    @guetti的回答对我很有用,但没有什么更新,关键是 parent_ptr

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