Django model inheritance: create sub-instance of existing instance (downcast)?

django models
django model multiple inheritance
django multi table inheritance
django model fields

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 pluggable apps. Quoting Malcolm Tredinnick:

More importantly, though, just as in Python you cannot "downcast" with Django's model inheritance. That is, if you've already created the User instance, you cannot, without poking about under the covers, make that instance correspond to a subclass instance that you haven't created yet.

Well, I'm in the situation where I need to integrate this 3rd party app with my existing user instances. So, if hypothetically I am indeed willing to poke about under the covers, what are my options? I know that this doesn't work:

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

There's no exception, but it breaks all kinds of stuff, starting with overwriting all the columns from django.contrib.auth.models.User with empty strings...

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.

Django model inheritance: create sub-instance of , Django model inheritance: create sub-instance of existing instance (downcast)? Taken from http://stackoverflow.com/a/4065189. gistfile1.txt. [Django-users] Django model inheritance: create sub-instance of existing instance (downcast)?

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

Django model inheritance: create sub-instance of , Django model inheritance: create sub-instance of existing instance (downcast)?. Hi, this ticket is seven years old Model inheritance¶ Model inheritance in Django works almost identically to the way normal class inheritance works in Python, but the basics at the beginning of the page should still be followed. That means the base class should subclass django.db.models.Model.

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.

Django model inheritance: create sub-instance of existing instance, Okay, I hate to answer my own question, especially since it is sort of a repeat of ( Django model inheritance: create sub-instance of existing instance (downcast)?� 3.python - Using south to refactor a Django model with inheritance; 4.inheritance - Determining Django Model Instance Types after a Query on a Base-class; 5.python - Single Table Inheritance in Django; 6.python - Django model inheritance: create sub-instance of existing instance (downcast)?

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.

Django: Two different child classes point to same parent class, To create a new instance of a model, instantiate it like any other Python class: instance def save(self, *args, **kwargs): # Check how the current values differ from with multi-table inheritance you may want to delete only a child model's data. Multi-table inheritance does not allow linking new instance of child model to existing parent model instance. → Multi-table inheritance: create child instance from existing parent comment:32 Changed 5 years ago by Aron Podrigal

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.

Model instance reference | Django documentation, I work as a developer (mostly Python/Django) at Elastic. 1. answer. 1 49 Django model inheritance: create sub-instance of existing instance (downcast)?. 50 Django: no such table: django_session 49 Django model inheritance: create sub-instance of existing instance (downcast)? 45 Fade out message after 10 seconds, clearing the input elements using jQuery

User Benjamin Wohlwend, Django model inheritance: create sub-instance of existing instance (downcast)? django - inlineformset_factory with more than one ForeignKeydjango class with� Site matching query does not exist. Lookup parameters were {'pk': 1} Open Project Shell python manage.py shell Create Site Object from django.contrib.sites.models import Site

Django: Two different child classes point to same parent , It is related to Django model inheritance: create sub-instance of existing instance (downcast)? which suggests how to add object with existing� Browse other questions tagged osx, postgresql, psycopg2, python You may be interested in these books. Learning Unix for OS X: Going Deep With the Terminal and Shell.

how to conditionally save a form using django mult, The primary key of the referenced object (the model instance’s pk attribute) To implement a many-to-many relation using GenericForeignKey, you need to manually create a model to connect carts with items. The Cart model remains roughly similar to what you have seen so far:

Comments
  • See code.djangoproject.com/ticket/7623
  • Excellent, thanks, Daniel. Got me out of this jam: stackoverflow.com/questions/18130124/….
  • You should exclude the pk from the dict or reset it to None before saving. See also the other answer. Otherwise you're just waiting for an IntegrityError.
  • man finally resolved . was stuck for too long on this problem . thanks
  • Does anyone know how to do this without re-saving/updating all of the fields?? I have tried to specify select update_fields in the save, but I can't figure out what I would need. I have tried (pk, id, user_ptr_id, and parent) and a bunch of more far fetched ones but none work!
  • This is giving me an error "cannot set attribute" when using through admin actions
  • This seems to work for all fields except ManyToMany fields, which unfortunately is an issue for me. Any ideas what to do if that is the case?