I\'m trying to integrate a 3rd party Django app that made the unfortunate decision to inherit from django.contrib.auth.models.User
, which is a big no-no for plu
I found this answer by asking on django-user mailing list:
https://groups.google.com/d/msg/django-users/02t83cuEbeg/JnPkriW-omQJ
This isn't part of the public API but you could rely on how Django loads fixture internally.
parent = Restaurant.objects.get(name__iexact="Bob's Place").parent
bar = Bar(parent=parent, happy_hour=True)
bar.save_base(raw=True)
Keep in mind that this could break with any new version of Django.
I am using Django 1.6, and my ExtendedUser
model is from OSQA (forum.models.user.User
). For some bizarre reason the above solutions with dict.__update__
and with setattr
sometimes fail. This may have to do with some other models that I have, that are putting constrains on the user tables. Here are two more workarounds that you can try:
Workaround #1:
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
Workaround #2:
extended_user = ExtendedUser(user_ptr_id = user.pk)
extended_user.__dict__.update(user.__dict__)
extended_user.id=None
extended_user.save()
That is, sometimes saving the new child instance fails if you set both pk
and id
, but you can set just pk
, save it, and then everything seems to work fine.
This should work:
extended_user = ExtendedUser(user_ptr_id=auth_user.pk)
extended_user.__dict__.update(auth_user.__dict__)
extended_user.save()
Here you're basically just copying over the values from the auth_user version into the extended_user one, and re-saving it. Not very elegant, but it works.
There is an open bug for this very question: https://code.djangoproject.com/ticket/7623
The proposed patch (https://github.com/django/django/compare/master...ar45:child_object_from_parent_model) is not using obj.__dict__
but creates an dictionary with all field values cycling over all fields.
Here a simplified function:
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, {})
This method has the advantage that methods that are overwritten by the child are not replaced by the original parent methods.
For me using the original answers obj.__dict__.update()
led to exceptions as I was using the FieldTracker
from model_utils
in the parent class.
@guetti's answer worked for me with little update => The key was 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()
I wanted to create entry in my profile model for existing user, my model was like
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)
At some place I needed to create profile if not exists for existing user so I did it like following,
The example that worked for me
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()
If you don't like __dict__.update
solution you can do this:
for field in parent_obj._meta.fields
setattr(child_obj, field.attname, getattr(parent_obj, field.attname))