Well, I personally have been saying for over a year that inheritance
has never been and never will be the right way to do that, so I think
y'all know what my answer is...
--
"Bureaucrat Conrad, you are technically correct -- the best kind of correct."
Because every app has its own concept/method of how to link info to a
User object, hence that information is best held in other models each
with a FK to the User.
Regards
Rajeev J Sebastian
http://www.b-list.org/weblog/2007/feb/20/about-model-subclassing/
Purely in terms of OO design, because it's cleaner. Object
composition is usually a more appropriate paradigm than class
inheritance. To take the example from the post that started this
thread, the relationship between users and user profiles is "has-a",
not "is-a". So what would be the design benefit of applying
inheritance here in the first place?
Not to get too much into this discussion, but I tend to be slow to
understand design patterns and other paradigms. What then would be the
appropriate way to handle an app that managed authors? I can see two
possibilities:
class Author(User):
pen_name = models.CharField(max_length=255)
or
class AuthorProfile(models.Model):
user = models.OneToOneField(User)
pen_name = models.CharField(max_length=255)
Essentially, whether it has the semantics of an "is-a" or a "has-a"
relationship seems to depend solely on what name I give the class.
Clearly a user could "be an" author, while he/she could instead "have
an" author profile.
How would I proceed in a situation like this?
-Gul
The main problem with this approach is multiple apps. For e.g., a site
may have a CMS, a blog, a forum, etc ... and if each app were to
subclass User .....
you get the picture. Thats why User should never be subclassed (for
this kind of purpose anyway). In fact, I would so far as to say "never
use inheritance, unless you really know what you are doing". of
course, Inheritance being the first thing people teach about OO doesnt
help at all.
regards
Rajeev J Sebastian
> *snip*
> class AuthorProfile(models.Model):
> user = models.OneToOneField(User)
> pen_name = models.CharField(max_length=255)
Now that QSRF has landed, this type of thinking leads me to: who's
working on 121-rewrite? And more importantly, can I offer my
assistance? :)
Things like this would be well served by being able to follow a
OneToOneField in both directions via a .select_related() (no extra
trip to the DB). We have several use cases, among them our own User
system based on django.contrib.auth, in which we currently use almost
exactly what you see above as our "extended profile" that would be
very useful to have the relationship work in both directions in queries.
I will hesitantly say too, *if* OneToOneFields were to work that way
and only generate a single query no matter which way they were
approached (and followed all the proper ForeignKeys on both sides), I
think it would end a good portion of the confusion/arguments about the
proper design patterns to use here, since the only major justification
left for not using the 121 mechanism would be on the saving side at
that point.
gav
I do not believe you understood what I mean by fixed. OneToOneField
has always worked, halfway. What it doesn't do is follow the
relationship in both directions:
from django.db import models
class A(models.Model):
a1 = models.CharField(max_length=20)
class B(models.Model):
b1 = models.CharField(max_length=20)
b2 = models.OneToOneField(A)
B.objects.select_related() creates this query (MySQL, taken from the
logs):
SELECT `t1_b`.`id`, `t1_b`.`b1`, `t1_b`.`b2_id`, `t1_a`.`id`,
`t1_a`.`a1` FROM `t1_b` INNER JOIN `t1_a` ON (`t1_b`.`b2_id` =
`t1_a`.`id`)
A.objects.select_related() creates this query:
SELECT `t1_a`.`id`, `t1_a`.`a1` FROM `t1_a`
A complete OneToOneField would generate effectively the same query in
both directions, since it's a special type of ForeignKey that the
reverse relationship makes sense to automatically select on.
If this worked, then in the User case, you could select_related() on
the UserProfile, *OR* .select_related() on the User(), and you would
get the same data either way, no matter how many models were connected
via OneToOneField in this manner. I would assume that all the
normal .select_related(***) options would work as well across this,
like "depth" and the new options for picking a subset of fields only
to follow the relations on.
(As an aside, forward FKs on both sides of the OneToOne should be
followed, but that I would assume is an incidental of getting
OneToOnes working this way in the first place).
Does that make more sense as to why it would alleviate the issue?
Thanks,
gav