Django’s great. It lets you prototype a web app extremely quickly, there’s good design philosophies that rub off onto your app, there’s great documentation… but there are also quite a few limitations I came across when trying to make my app. Thankfully, like I said, there’s great documentation, which includes ways to get around these limitations. Here are the obstacles I came across when building my course management app, Whiteboard, and how I got around each of them.
Dealing with foreign keys to abstract model classes
I had an UploadedItem abstract model class and I wanted to let people comment on UploadedItems. In an ideal world, I would be able to write the Comment model class like this:
class Comment(models.Model):
comment = models.TextField()
uploader = models.ForeignKey(User)
upload_date = models.DateTimeField("Date uploaded", editable=True)
uploaded_item = models.ForeignKey(UploadedItem)
But then you’d get an error saying that you can’t specify an abstract class as a foreign key, which makes sense since Django doesn’t actually implement the abstract model class in the database.
Solution:
The contenttypes framework! More specifically, generic relations. In the end comment looks like this:
class Comment(models.Model):
comment = models.TextField()
uploader = models.ForeignKey(User)
upload_date = models.DateTimeField("Date uploaded", editable=True)
# Following fields are required for using GenericForeignKey
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
uploaded_item = generic.GenericForeignKey()
Also, to get the reverse relation from my UploadedItem instances such as Announcement, I had to include a comments GenericRelation field in each of the UploadedItem instances where I wanted to allow comments for.
class Announcement(UploadedItem):
"""Announcement"""
announcement = models.TextField()
comments = generic.GenericRelation(Comment)
So now, to get all the comments for an announcement, all I would have to do is:
>>> announcement.comments.all()
It might not be the simplest solution, but it really is simple enough, and after I followed instructions from the documentation, it really just worked. Pity I couldn’t have it the “ideal” way, but then again using the contenttypes framework made the final implementation simple enough.
(Next post on making models and forms dynamic)