Model Inheritance caveat

138 views
Skip to first unread message

Rein Petersen

unread,
Aug 1, 2008, 10:05:52 AM8/1/08
to Google App Engine
Hi All,

I'm using Model inheritance to distinguish distinguish entities that
are, essentially, the same. Usually, inheritance involves extending
the base class with more properties (and such) defined in the
subclasses but in my instance, extension is not required - only
distinction. An example is provided below.

The problem is that an exception is raised when there is no code below
the class definition:

<type 'exceptions.IndentationError'>: expected an indented block

I could easily give up using inheritance and define the properties on
each model separately, or I could continue with inheritance but pull
one property out of the base and repeat it in the subclasses but it
pains me to do so.

I was wondering if there were some little bit of insignificant I place
in the subclass definitions that would satisfy the interpreter to
avoid the IndentationError exception... Thanks Rein :)

*** Example :: models.py
class Place(db.Model):
# abstract
name = db.StringProperty()
geo = db.GeoPtProperty()

class Continent(Place):
# represents a continent

class Continent(Place):
# represents a continent

class Country(Place):
# represents a country

class Region(Place):
# represents a region

class City(Place):
# reprecents a city

Blixt

unread,
Aug 1, 2008, 10:09:29 AM8/1/08
to Google App Engine
You use the 'pass' keyword in Python to skip an implementation:
class Region(Place):
pass

Also worth noting is that data-wise, those models will have no
relation to eachother in the datastore, so you can only query for one
type at a time. Just in case you didn't consider it, might save you
some time :)

Regards,
Andreas

Rein Petersen

unread,
Aug 1, 2008, 10:30:28 AM8/1/08
to Google App Engine
Andreas, thanks for that :)
I'll be relating the entities using parent-child relationships. It is
unfortunate that you cannot query a base model and find the subclasses
- oh well, don't want to throw the baby out with the bathwater...
Thanks again,
Rein

Blixt

unread,
Aug 1, 2008, 11:18:43 AM8/1/08
to Google App Engine
I have written an extension to the Model class that will enable you to
query base models (classes) and get their sub-models: http://paste.blixt.org/505
It does add some overhead, of course, but I haven't really benchmarked
it. It shouldn't slow down things too much, though.

Regards,
Andreas

Calvin Spealman

unread,
Aug 1, 2008, 1:25:05 PM8/1/08
to google-a...@googlegroups.com
Usually this kind of dependence on type is frowned upon in Python. If
the only difference between classes is the name, and otherwise they
are completely identical: the name should be the same too. I've never
seen a good reason to do this, and I've seen dozens of people with
cases where they thought it was a good idea. Another design has always
prevailed.

Are these all not simply "places"? Why not add a CategoryProperty?

--
Read my blog! I depend on your acceptance of my opinion! I am interesting!
http://ironfroggy-code.blogspot.com/

Blixt

unread,
Aug 1, 2008, 4:43:21 PM8/1/08
to Google App Engine
I agree. Something like:
class Area(db.Model):
CONTINENT = 1
COUNTRY = 2
REGION = 3
CITY = 4

name = db.StringProperty()
geo = db.GeoPtProperty()
level = db.IntegerProperty(choices = [Area.CONTINENT, Area.COUNTRY,
Area.REGION, Area.CITY])

Calvin Spealman

unread,
Aug 1, 2008, 7:11:27 PM8/1/08
to google-a...@googlegroups.com
There is an actual CategoryProperty that could be used.

Although, I'll be honest, I'm not really sure what the direct value is
with things like the Category and Rating property types. I mean, what
is it abstracting for us? Whats the point?

Rein Petersen

unread,
Aug 2, 2008, 2:26:12 PM8/2/08
to Google App Engine
Thanks for the advice but I remain skeptical - I prefer that the
entities are stored in separate groups for speed's sake. If I want to
fetch Continents (there are only 7), I don't want to search an entity
group that includes 100's of 1000's of cities, regions, and
countries... Also, I do expect to uniquely extend the subclasses with
properties - I just don't know what they are yet... I'm still
designing.

Calvin, I'm curious why this is frowned upon in Python. Can you tell
me why or where I can read more about it? I'm so accustomed
abstracting and normalizing "all the way" as good OO and db design,
but if this can be problematic in some instances with Python and/or
with the GAE datastore, I want to know - my purpose is to design for
performance and scalability on this platform and I am all ears on the
matter.

Thanks again for all the advice :)
Rein

Calvin Spealman

unread,
Aug 3, 2008, 1:01:14 AM8/3/08
to google-a...@googlegroups.com
If you expect to actually add distinguishing behavior to the
subclasses, thats good. What is frowned upon is subclasses for the
sake of identifying different logical types that otherwise have
identical behavior. It boils down to how you tell the difference
between objects, if you ever need to. Now, in any ideal case, we don't
need to distinguish. A function expects a certain behavior in its
parameters (not necessarily a certain type) and if you have different
kinds of objects that should come in, they should act enough the same
that the function doesn't need to know. You just need to know they all
behave the same on the outside.

The speed argument could count for something, but an index on the
category property would solve that.

David Symonds

unread,
Aug 3, 2008, 1:08:55 AM8/3/08
to google-a...@googlegroups.com
On Sun, Aug 3, 2008 at 4:26 AM, Rein Petersen <rein.p...@gmail.com> wrote:

> Thanks for the advice but I remain skeptical - I prefer that the
> entities are stored in separate groups for speed's sake. If I want to
> fetch Continents (there are only 7), I don't want to search an entity
> group that includes 100's of 1000's of cities, regions, and
> countries...

Separate "groups" are largely irrelevant for the datastore; that's one
of the key differences between it and a regular SQL system. Objects
are keyed uniquely, regardless of their "type".
Using the filters (and thus indexes) is going to be fast enough,
especially if you start memcaching the common parts of it.


Dave.

g-man

unread,
Aug 3, 2008, 9:59:12 AM8/3/08
to Google App Engine
My supposition as to all the specialized properties is that they have
built-in xml and json meanings, just like the phone number, postal
address, etc. Otherwise, yes, you could just use primitive data types
for everything, like SQLite does - I think you only need about four
data types for that implementation.

Jorge Vargas

unread,
Aug 3, 2008, 5:50:00 PM8/3/08
to google-a...@googlegroups.com
On Sat, Aug 2, 2008 at 12:26 PM, Rein Petersen <rein.p...@gmail.com> wrote:
>
> Thanks for the advice but I remain skeptical - I prefer that the
> entities are stored in separate groups for speed's sake. If I want to
> fetch Continents (there are only 7),

well for one I wouldn't store that in the db. I don't think it will be
mutable enough :)

> I don't want to search an entity
> group that includes 100's of 1000's of cities, regions, and
> countries... Also, I do expect to uniquely extend the subclasses with
> properties - I just don't know what they are yet... I'm still
> designing.
>

> Calvin, I'm curious why this is frowned upon in Python. Can you tell
> me why or where I can read more about it? I'm so accustomed
> abstracting and normalizing "all the way" as good OO and db design,

this has no relevancy in python, it's just that python's OOP is way
beyond the typical restrictions of type-based-class objects.

I'll really suggest trying to see if you don't need the extra types
just to label them. Aren't they all locations?

> but if this can be problematic in some instances with Python and/or
> with the GAE datastore, I want to know - my purpose is to design for
> performance and scalability on this platform and I am all ears on the
> matter.

datastore is new and therefore we need to figure out the best
practices, and so far the conclusion is that data normalization, in
the SQL sense, is not a great idea. in appengine the less "joins" you
have the better.

allyourcode

unread,
Apr 13, 2013, 1:48:49 PM4/13/13
to google-a...@googlegroups.com, rein.p...@gmail.com
There is PolyModel, which will return subclass instances when queried. Not sure if that existed at the time, but it sounds like exactly what you are looking for. e.g.

from google.appengine.db import polymodel  # ndb also has this

class P(polymodel.PolyModel): pass
class C1(P): pass
class C2(P): pass

P.all()  # May return instances of C1 and/or C2.

allyourcode

unread,
Apr 13, 2013, 1:57:06 PM4/13/13
to google-a...@googlegroups.com, rein.p...@gmail.com


On Saturday, August 2, 2008 11:26:12 AM UTC-7, Rein Petersen wrote:
Thanks for the advice but I remain skeptical - I prefer that the
entities are stored in separate groups for speed's sake. If I want to
fetch Continents (there are only 7), I don't want to search an entity
group that includes 100's of 1000's of cities, regions, and
countries...

Datastore queries are designed to scale with the number of results, not the number entities. It shouldn't matter that your 100s of countries are mixed with 10000s of cities. If you find that it does, report it.

Having said that, putting continents into Datastore may be going for too much purity and/or elegance. Geological shifts happen slowly enough that your app (and the rest of civilization?) probably won't be around by the time South America and Africa reunite, or California sucedes from North America.
 
Also, I do expect to uniquely extend the subclasses with
properties - I just don't know what they are yet... I'm still
designing.

Calvin, I'm curious why this is frowned upon in Python. Can you tell
me why or where I can read more about it? I'm so accustomed
abstracting and normalizing "all the way" as good OO and db design,
but if this can be problematic in some instances with Python and/or
with the GAE datastore, I want to know - my purpose is to design for
performance and scalability on this platform and I am all ears on the
matter.

Your idea to model with subclasses sounds good to me. This seems to be something that PolyModel was designed for.
Reply all
Reply to author
Forward
0 new messages