Re: dynamic upcast

2008-10-23 Thread Carl Meyer

Hi harold,

On Oct 23, 9:27 am, dadapapa <[EMAIL PROTECTED]> wrote:
> If by "save a derived object from a parent instance" you mean that
> the method that saves the object is defined in the parent class,
> than this should not cause a problem, since type(self) will
> dynamically identify the object as being of the derived type,
> so final_type gets initialized correctly. Then again, I might have
> misunderstood your problem.

Sorry, I wasn't clear.  You may have a BaseClass instance that is
"really" a DerivedClass, and if you ever call save() from that
BaseClass instance (without casting it to a DerivedClass first), the
recipe will break.  Code is clearer:

>>> d = DerivedClass.objects.create()
>>> d.final_type

>>> d2 = BaseClass.objects.all()[0]
>>> d2.final_type

>>> d2.save()
>>> d2.final_type


The fix is just to add an "if not self.id" in the save() method, so
the "final_type" is only set once, at creation time, not on every
save:

def save(self, *args, **kwargs) :
if not self.id:
self.final_type =
ContentType.objects.get_for_model(type(self))
super(BaseClass, self).save(*args)

Carl
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en
-~--~~~~--~~--~--~---



Re: dynamic upcast

2008-10-23 Thread dadapapa

On Oct 19, 10:10 pm, Carl Meyer <[EMAIL PROTECTED]> wrote:
> Just ran into this issue myself (first time using non-abstract
> inheritance).  The catch with this recipe is that you can never save a
> derived object from a parent instance, or you break the final_type
> field (it will then contain the parent class content type).

If by "save a derived object from a parent instance" you mean that
the method that saves the object is defined in the parent class,
than this should not cause a problem, since type(self) will
dynamically identify the object as being of the derived type,
so final_type gets initialized correctly. Then again, I might have
misunderstood your problem.

Cheers,

- harold -

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en
-~--~~~~--~~--~--~---



Re: dynamic upcast

2008-10-19 Thread Carl Meyer



On Sep 12, 2:57 pm, dadapapa <[EMAIL PROTECTED]> wrote:
>     class BaseClass(models.Model) :
>         final_type = models.ForeignKey(ContentType)
>
>         def save(self,*args) :
>             self.final_type =
> ContentType.objects.get_for_model(type(self))
>             super(BaseClass,self)save(*args)
>
>         def cast(self) :
>             return
> self.final_type.get_object_for_this_type(id=self.id)
>
>     class DerivedClass(ParentClass) :
>         pass

Just ran into this issue myself (first time using non-abstract
inheritance).  The catch with this recipe is that you can never save a
derived object from a parent instance, or you break the final_type
field (it will then contain the parent class content type).

Carl
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en
-~--~~~~--~~--~--~---



Re: dynamic upcast

2008-09-16 Thread dadapapa

Hi Malcolm,

Malcolm Tredinnick wrote:
> > class BaseClass(models.Model) :
> > final_type = models.ForeignKey(ContentType)
> >
> > def save(self,*args) :
>
> For absolute robustness, you should also accept **kwargs here. There are
> a couple of places in Django's code that will call save() and pass in
> force_insert=True, for example, which won't be handled by *args. In
> reality, all you need to be able to handle is force_insert and
> force_update, but *args and **kwargs are also pretty useful,
> particularly if you aren't doing anything with them except passing them
> along.

thanks for the suggestion. What you say is, of course, true.

> > self.final_type =
> > ContentType.objects.get_for_model(type(self))
> > super(BaseClass,self)save(*args)
> >
> > def cast(self) :
> > return
> > self.final_type.get_object_for_this_type(id=self.id)
> >
> > class DerivedClass(ParentClass) :
> > pass
> >
> > Here is an example:
> >
> > obj = DerivedClass()
> > obj.save()
> >
> > obj = get_object_or_404(BaseClass, id=3).cast()
> > # obj is now of type DerivedClass
>
> Yes, well done. This looks like the right way to handle this. Glad
> somebody's documented it here.

Thanks. In principle, I think there is still room for optimization:
the database gets hit twice, and it would be sufficient to return
only the 'final_type' field in the first call, especially if the base
class
is voluminous. Since this is possible to do it in SQL, it shouldn't
be hard to do it in django, too, but I didn't have time to implement
this yet.

Cheers,

- harold -

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en
-~--~~~~--~~--~--~---



Re: dynamic upcast

2008-09-16 Thread Malcolm Tredinnick


On Fri, 2008-09-12 at 11:57 -0700, dadapapa wrote:
> > It does not work at all. For some reason, final_type also gets
> > upcasted to MediaObject?!
> 
> I found the solution, now. The problem was that the __init__ method of
> a Model is also called when objects are restored from the database. So
> when the base class gets initialized by the QueryManager, it
> overwrites final_type with the wrong value. The solution is simple:
> overwrite the save method instead of __init__. Here is a complete
> recipe:
> 
> class BaseClass(models.Model) :
> final_type = models.ForeignKey(ContentType)
> 
> def save(self,*args) :

For absolute robustness, you should also accept **kwargs here. There are
a couple of places in Django's code that will call save() and pass in
force_insert=True, for example, which won't be handled by *args. In
reality, all you need to be able to handle is force_insert and
force_update, but *args and **kwargs are also pretty useful,
particularly if you aren't doing anything with them except passing them
along.

> self.final_type =
> ContentType.objects.get_for_model(type(self))
> super(BaseClass,self)save(*args)
> 
> def cast(self) :
> return
> self.final_type.get_object_for_this_type(id=self.id)
> 
> class DerivedClass(ParentClass) :
> pass
> 
> Here is an example:
> 
> obj = DerivedClass()
> obj.save()
> 
> obj = get_object_or_404(BaseClass, id=3).cast()
> # obj is now of type DerivedClass

Yes, well done. This looks like the right way to handle this. Glad
somebody's documented it here.

Regards,
Malcolm



--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en
-~--~~~~--~~--~--~---



Re: dynamic upcast

2008-09-12 Thread dadapapa

> It does not work at all. For some reason, final_type also gets
> upcasted to MediaObject?!

I found the solution, now. The problem was that the __init__ method of
a Model is also called when objects are restored from the database. So
when the base class gets initialized by the QueryManager, it
overwrites final_type with the wrong value. The solution is simple:
overwrite the save method instead of __init__. Here is a complete
recipe:

class BaseClass(models.Model) :
final_type = models.ForeignKey(ContentType)

def save(self,*args) :
self.final_type =
ContentType.objects.get_for_model(type(self))
super(BaseClass,self)save(*args)

def cast(self) :
return
self.final_type.get_object_for_this_type(id=self.id)

class DerivedClass(ParentClass) :
pass

Here is an example:

obj = DerivedClass()
obj.save()

obj = get_object_or_404(BaseClass, id=3).cast()
# obj is now of type DerivedClass

Best,

- harold -
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en
-~--~~~~--~~--~--~---