Best way to accomplish model inheritance

4 views
Skip to first unread message

Aaron Jacobs

unread,
Dec 22, 2006, 11:44:42 PM12/22/06
to Django users
Hey everyone,

I'm currently attempting to design my first Django application. The
model framework seems to be pretty nice -- it reminds me a bit of
Apple's Core Data, except more geared toward web development.

The model for my application conceptually needs something like model
inheritance, as described near the beginning of the [wiki article] [1]
of the same name. That is, I would love to do something like the
following:

class Place(models.Model):
name = models.CharField(maxlength=50)

class Restaurant(Place):
type_of_food = models.CharField(maxlength=50)

class Hotel(Place):
price_per_night = models.FloatField()

This models the 'object-oriented' nature of things -- restaurants and
hotels are both places and should thus share the properties of places.

Being a Cocoa/Core Data guy myself, the snippet above is the most
natural way I can think of to do things. It sounds like Django is
moving toward that, but I'm disappointed to see that doing it that way
and having things automatically sorted out by the model layer isn't
possible today.

So can anyone tell me what the best way is to model such a relationship
is _today_? It looks like a one-to-one key might work, but the
reference documentation warns against it and, more importantly, I'm not
positive it will do exactly what I want and don't exactly know how to
accomplish it. I've seen some relevant discussions in the list
archives, but they are a bit old and mostly related to the admin
interface, which I am not extremely concerned with.

Here are some points I'm looking for. They're mostly just what you
would expect from an object-oriented system (and how things work in
Core Data). Hopefully someone can tell me how to accomplish all of
this.

1. If I ask for a list Places matching certain criteria, then Hotels,
Restaurants, and basic Places matching the criteria should all be
returned.

2. If I get a list of Places as above, then I should be able to tell
whether a given object in the list is a Hotel or Restaurant or whatever
and get and set its associated properties.

3. Restaurants and Hotels should be their own independent entities. If
there is some crazy stuff going on with foreign keys and multiple
tables behind the scenes, it should stay behind the scenes as an
implementation detail. So if I delete a Hotel object, it should
automatically delete the associated Place object if there is such a
thing in the implementation.

Can anyone help me with this? So far it's the only thing I've come
across in Django that doesn't seem natural and well thought out.

Thanks in advance for any help.
Aaron

[1]: http://code.djangoproject.com/wiki/ModelInheritance

favo

unread,
Dec 24, 2006, 10:19:10 AM12/24/06
to Django users
Hi Aaron,

I know there're two way to use model inheritance with current django.
both are not perfect, you could choice what you need. That's say model
inheritance is still not a feature of django, but should be one imo.

1. as you said, use OneToOne field


class Place(models.Model):
name = models.CharField(maxlength=50)

class Restaurant(models.Model):
place = models.ForeignKey(Place)
type_of_food = models.CharField(maxlength=50)

The problems are:
* very hard to use it will Admin interface. Current Admin only
support edit_inline, that means edit Restaurant in Place, but what you
need it's kind of "edit_outline" -- edit Place in Restaurant.
* without OO inheritance power, you need remeber which field in
Place, which field in Restaurant.

2. use OO inheritance, current django support inheritance model --
inheritance all parent fields to child.


class Place(models.Model):
name = models.CharField(maxlength=50)

class Restaurant(Place):
type_of_food = models.CharField(maxlength=50)

# fix default manager
_default_manager = Model.Manager()
_default_manager.model = Restaurant
Restaurant._default_manager= Restaurant.objects =
_default_manager

the way is firendly to Admin and easy to search.
The problems are:
* default manager don't work, you have to fix it outside the classs
definition.
* restautant have parents all fields in database. that's not a
problem for us.

> 1. If I ask for a list Places matching certain criteria, then Hotels,
> Restaurants, and basic Places matching the criteria should all be
> returned.

In second way need sync the child field with the base instance.

>
> 2. If I get a list of Places as above, then I should be able to tell
> whether a given object in the list is a Hotel or Restaurant or whatever
> and get and set its associated properties.

In both way, you have to have a genericFK in base model(point to child
instance), and maintain it when call child.save. so you can return a
base model queryset and regroup them by content_type.

> 3. Restaurants and Hotels should be their own independent entities. If
> there is some crazy stuff going on with foreign keys and multiple
> tables behind the scenes, it should stay behind the scenes as an
> implementation detail. So if I delete a Hotel object, it should
> automatically delete the associated Place object if there is such a
> thing in the implementation.

In both way you have to do it yourself, but you could use signals have
you to do it automatically.

I can see there're more ways described in[1], but seems those way have
it own problems. you could try.


[1] http://code.djangoproject.com/wiki/ModelInheritance

Aaron Jacobs

unread,
Dec 24, 2006, 1:04:33 PM12/24/06
to django...@googlegroups.com
Thanks so much for the tips, Favo. There are some points that are
unclear to me, so I hope you don't mind if I ask a few questions.

On 12/24/06, favo <Favo...@gmail.com> wrote:
>
> 1. as you said, use OneToOne field
>
> class Place(models.Model):
> name = models.CharField(maxlength=50)
>
> class Restaurant(models.Model):
> place = models.ForeignKey(Place)
> type_of_food = models.CharField(maxlength=50)

Should that be a `OneToOneField` instead of a `ForeignKey`?

> 2. use OO inheritance, current django support inheritance model --
> inheritance all parent fields to child.
> class Place(models.Model):
> name = models.CharField(maxlength=50)
>
> class Restaurant(Place):
> type_of_food = models.CharField(maxlength=50)
> # fix default manager
> _default_manager = Model.Manager()
> _default_manager.model = Restaurant
> Restaurant._default_manager= Restaurant.objects =
> _default_manager

Where does that default manager code go? It's not in the class
definition, is it?

In fact, do you happen to have a more complete piece of code that uses
this approach and could be shared with the list?

> > 1. If I ask for a list Places matching certain criteria, then Hotels,
> > Restaurants, and basic Places matching the criteria should all be
> > returned.
>
> In second way need sync the child field with the base instance.

I don't understand your response here. Can you give a code snippet?

> > 3. Restaurants and Hotels should be their own independent entities. If
> > there is some crazy stuff going on with foreign keys and multiple
> > tables behind the scenes, it should stay behind the scenes as an
> > implementation detail. So if I delete a Hotel object, it should
> > automatically delete the associated Place object if there is such a
> > thing in the implementation.
>
> In both way you have to do it yourself, but you could use signals have
> you to do it automatically.

Can you give an example of this? I'm not familiar with signals.


Again, thanks a lot for taking the time to respond.

Aaron

Reply all
Reply to author
Forward
0 new messages