On Thu, 2009-01-08 at 19:46 -0800, Cortland Klein wrote: > Hi. I'm planning on extending Group for a GroupProfile. I noticed that > the recommended way to extend User is to create a UserProfile with a > ForeignKey(User, unique=True) instead of a OneToOneField[a]. > > 1. Why is it recommended to use a ForeignKey(unique=True) from a > UserProfile to User instead of a OneToOneField or subclassing User for > multi-table inheritance?
Partly historical. Prior to the queryset-refactor branch being merged into trunk, we weren't recommending that people used OneToOneField, as it had a few internal problems. That was subsequently tidied up and OneToOneField is a grade A field again these days. Similarly for model inheritance (although see the next paragraph for the real problem here). It was only added to Django last year, but the user profile concept has been around for ages. There's also an element of explicitness involved: using the related field and including it explicitly makes it clear what's going on. Model inheritance is, in many ways, a bit of a cheat to make something look Pythonic that really isn't (the relational database structure of the storage leaks through in a few ways). More importantly, though, just as in Python you cannot "downcast" with Django's model inheritance. That is, if you've already created the User instance, you cannot, without poking about under the covers, make that instance correspond to a subclass instance that you haven't created yet. Since user profiles are always created after the User instance (possibly via the post_save signal, but that's the earliest you can do it), this is a bit of a problem. On the other hand, it's easy and documented how to add a user profile class at a later stage after the user is created (you can simulate "downcasting", but you end up having to admit that the multi-table inheritance is done with a OneToOneField and poking at a hidden field and possibly having to sacrifice a chicken, so you might as well just right it out explicitly in the first place). > 2. As I'm planning on extending Group with GroupProfile, should I use > a ForeignKey(Group, unique=True), a OneToOneField(Group), or have > GroupProfile subclass Group to use Multi-table interitence? Does it > even matter since Group currently has no get_profile() function anyways? These days, if you're implementing something that really is one-to-one, I would recommend the OneToOneField. In fact, I suspect there's probably no reason it can't be used for the User profile class, either. The only significant difference between OneToOneField and ForeignKey(unique=True) is when you're traversing the reverse relation. If you have class ModelA(models.Model): ... class ModelB(models.Model): related = Models.OneToOneField(ModelA) ... and obj_a is a ModelA instance, then obj_a.modelb will return a ModelB instance. On the other hand, if ModelB is using a ForeignKey(ModelA, unique=True) setup, obj_a.modelb_set.all() is the required spelling and will return an iterator containing a single ModelB instance. So, for single instance things, OneToOneField provides a more natural API -- you immediately get hold of the object you care about. Note, however (in case you care) that User.get_profile() doesn't use the reverse relation, which is why you can switch OneToOneField and ForeignKey there. It does an explicit get() call to retrieve the instance with the correct primary key. 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 django-users+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/django-users?hl=en -~----------~----~----~----~------~----~------~--~---