Say your building the standard blog application. It's conceivable that
you'd want your users to add comments, add tags, and rate posts.
You might have a model for comments which looks slightly like this.
class Comment(models.Model):
post = models.ForeignKey(BlogPost)
author = models.ForeignKey(User)
comment_text = models.TextField(blank=True)
something similar for tags and ratings.
Then you expand your site to add your photos, and you'd like to allow
the same features to be used, and, in fact, the same code to be used.
Trouble is, the models you've defined specifies that Comments work with
BlogPosts.
Now looking at the django.contrib.comments code I see that the author
there decided to use an integer object id rather than a ForeignKey
class Comment(models.Model):
parent = models.IntegerField(('object ID'))
author = models.ForeignKey(User)
comment_text = models.TextField(blank=True)
Ok, this means that the Comment can be used with any other item
(assuming it has an integer primary key), but we've got BlogPosts and
Photos on our site, and their object ids are not guaranteed to be
unique (in fact they're likely not to be). Also we've lost the nice
django DB API for traversing this relationship.
I can think of a few solutions, but don't know how to implement them.
1) Add a type_id field to the Comment model, which identifies which
table the object_id should be looked up in. I think most SQL databases
have a 'Table of Tables', but my SQL isn't good enough to know if this
is standard or not, and my django isn't good enough to know how to get
at it. Maybe it would need to be the name of the table in a varchar.
2) Have two tables containing Comments (one for BlogPosts and one for
Photos). I don't think django supports this at the moment as 1 class
appears to equal 1 table.
3) implement a 'Super'Key field which behaves like a foreignkey (i.e.
preserves the django DB API), but is able to refer to any object in any
table (possibly by storing info like (1))
Does anybody have any suggestion as to how any of these could be done?
I know this isn't really something that SQL supports, but I'm hopeful
it's possible to fake.
Thanks
Paul
Have another look at the Comment model in django.contrib.comments. See
the content_type field? That provides the mapping to the right model to
use to look up the object_id. The ContentType model in Django exists to
do exactly what you are asking here: provide indirect references to
other models that are determined at run-time, rather than definition
time.
Also have a look at the GenericRelation model field that was recently
added to Django. It's not fully documented yet, nor fully supported in
the admin, but the tests provide an example of how to use it:
http://code.djangoproject.com/browser/django/trunk/tests/modeltests/generic_relations/models.py
I think you'll find that GenericRelation can help you achieve most of
what you are after. It provides exactly the sort of model-independent
lookup you seem to be seeking.
Regards,
Malcolm
I also found Luke Plant's tagging app
(http://groups.google.com/group/django-users/browse_thread/thread/a7cbd4fd843583be)
in which he has a GenericForeignKey, but I'll investigate the core
version first.
Thanks again.
Paul
Cheers,
Chris
Yeah, once I started looking at the code I saw the commit logs that
said the same thing. Good to see things growing that quickly.
It's nice to think I was having ideas about solving it in a similar
way. I must be starting to think Django, but I'd have had no clue about
implementing it
Can I just say thanks again to Malcolm for pointing me at the unit
tests. I'd never realized they were there and they're a great resource
for learning how to use particular features, especially in the database
API. A number of things which don't appear to be documented in the
normal documentation have tests with good explanations as to how they
work.
I've worked out how to do a number of things I was unclear on from
looking at those.
You're welcome. :-)
> I'd never realized they were there and they're a great resource
> for learning how to use particular features, especially in the database
> API. A number of things which don't appear to be documented in the
> normal documentation have tests with good explanations as to how they
> work.
The tests are used to generate the examples on the Django website:
http://www.djangoproject.com/documentation/models/ . There is one line
in the model-api.txt file that points you to them, too (since they are
on the website, but otherwise hidden in the distribution). However, it
wouldn't be too hard to miss that reference if you were in a rush.
Regards,
Malcolm