On Wed, Apr 21, 2010 at 5:09 PM, Tim Shaffer <t...@tim-shaffer.com> wrote:
> I think then you will run into a problem with you add another media
> type:
>
> class WAVMedia(Media):
>  file = models.CharField()
>  def play(self):
>    # do stuff
>
>>>> m = Media()
>>>> m.wavmedia = WAVMedia()
>>>> m.mp3media = MP3Media()
>>>> playlist = Playlist
>>>> playlist.media_set.append(m)
>
> for media in playlist.media_set.all():
>  media.play()
>
> Should media.play() call play() on the Media class, WAVMedia class, or
> the MP3Media class? It *should* call it on the Media class, which it
> does, since you have an instance of Media. And even you wanted it to
> call the play method on MP3Media or WAVMedia, how would you determine
> which one to call? But this is the way multiple table inheritance is
> supposed to work. This is the way python works:

Well, no clearly not - those are all base instances. The point is that
polymorphism, forget python or django for a second, a standard feature
of most programming languages would say that if you get a Derived type
addressed as a Base type, then calling a virtual function on it would
call the Derived method.

Python sorts this out by not allowing you to alias a Derived type as a
Base type, except explicitly by calling the Base type as a class
function and passing in a Derived instance as 'self'. If you create an
instance of Base, its not a Derived - ever!

With Django's MTI, you *can* get a Derived type aliased as a Base
type, due to the way MTI works. This isn't a problem (it certainly
isn't one for me!), it's just something to be aware of. The OP wasn't,
and that's why we're having this discussion!

>
> class Media(object):
>    pass
>
> class MP3Media(object):
>    def play(self):
>        # pass
>
> If I have the following list:
>
> songs = [ Media(), Media(), Media() ]
>
> I would never expect to be able to call play() on any instance in that
> list. Why would Django be any different?



>
> I think in both these cases (there is no person actually an instance
> of "Person", and there should be no actual instance of "Media"), it
> would be best to mark the parent class abstract and use a generic
> relation (like you said) to join to either MP3Media or WAVMedia. This
> is the "Django way" and I believe is the functionality you're looking
> for.

No, it really isn't. I've obviously missed off a whole slew of things
from this example model, but there are a HOST of common options for a
Media class that are generic and non-specific to a type of Media. Not
storing this homogeneously would be a bit crap, don't you think? You
wouldn't be able to find media with a playlength more than 5 minutes,
only MP3Media, or WAVMedia, or....

As I mentioned, GFKs are the way to achieve the solution, which does
do everything needed, there's just no need to go to abstract
inheritance. I'd alter your models to not use abstract inheritance,
add a GFK on Media to point at the specific instance of the media:

class Media(models.Model):
  content_type = models.ForeignKey(ContentType)
  object_id = models.PositiveIntegerField()
  media = generic.GenericForeignKey()

class MP3Media(Media):
  def play(self):
    print "playing mp3"

class WAVMedia(Media):
  def play(self):
    print "playing wav"

class Playlist(models.Model):
  media = models.ManyToManyField('Media')

for m in my_playlist.media_set.all():
  m.media.play()

This is what I was trying to say in my previous reply ;)

Cheers

Tom

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

Reply via email to