Using ContentType to link two different objects together

28 views
Skip to first unread message

Some Developer

unread,
Nov 5, 2014, 1:10:58 PM11/5/14
to django...@googlegroups.com
Hi,

I'm trying to write my own implementation of the Django comments
framework for various reasons and am wondering how one would link
comments to a particular object (model) of another type. For instance I
could have a ForeignKey in the Comment model pointing to a Blog post
article but that would mean that you could only leave comments on Blog
post articles. I want to be able to configure my Comment model so that
it can link to any other object of any type.

Does anyone know how to do that? I think it has something to do with the
ContentType framework that comes with Django but I have never used it
before so I'm not entirely sure.

Any help is appreciated.

Carl Meyer

unread,
Nov 5, 2014, 1:16:43 PM11/5/14
to django...@googlegroups.com
Hi,
I think this is what you're looking for:
https://docs.djangoproject.com/en/1.7/ref/contrib/contenttypes/#generic-relations

However, by using GenericForeignKey you give up some valuable things:
the database can no longer enforce referential integrity on those
relationships, and joins become more complex and often slower. So I
would recommend at least considering alternatives.

One possible alternative is to instead provide the bulk of your Comment
model as an abstract base model class, and then have users of your
comment app create their own Comment model inheriting from your abstract
base, and adding a single FK to whatever model they want comments on.
(This presumes that most users of your comments app will only need
comments on a single model in a given system; or if they want comments
on more than one model, they don't mind having two separate Comment
models to handle that.)

Carl

Some Developer

unread,
Nov 5, 2014, 1:36:11 PM11/5/14
to django...@googlegroups.com
Thanks for the info. You make some interesting points about the database
not being able to enforce referential integrity.

I hadn't thought of providing the comment model as a base class and
having the users specialise it themselves. How would that work in
regards to template tags? For instance if I had a template tag like this:

{% get_comments for obj as var %}

how would one hook in a user provided object with its own model which is
not known ahead of time or would you suggest using a template tag such
as this instead? I guess letting the user explicitly state the
application and the model themselves offers the best flexibility in the
long run.

{% get_comments for [app].[model] [object_id] %}

Carl Meyer

unread,
Nov 5, 2014, 1:47:46 PM11/5/14
to django...@googlegroups.com
> Thanks for the info. You make some interesting points about the database
> not being able to enforce referential integrity.
>
> I hadn't thought of providing the comment model as a base class and
> having the users specialise it themselves. How would that work in
> regards to template tags? For instance if I had a template tag like this:
>
> {% get_comments for obj as var %}
>
> how would one hook in a user provided object with its own model which is
> not known ahead of time

In order to make this template tag work, your comments app just needs to
know what comment model exists for any given "commentable" model. You
could ask the user to explicitly tell you this, by calling some kind of
registration function. Or you can just listen to the `class_prepared`
signal [1], which fires after every model class is prepared; check if
the model class is a subclass of your abstract Comment base; if it is,
check for the required added FK (throw a clear error if they didn't add
it), see what model class it's pointing to, and add it to your registry.

or would you suggest using a template tag such
> as this instead? I guess letting the user explicitly state the
> application and the model themselves offers the best flexibility in the
> long run.
>
> {% get_comments for [app].[model] [object_id] %}

I don't think this variant of the template tag really helps anything;
given an `obj`, you can quite easily figure out what model class it's an
instance of (`obj.__class__` or `obj._meta.model`). You still have to
get from that "commentable" model class to its comment model class,
which requires the same registry I described above.

So I'd probably go with the first version, which is an easier API for
the template author.

Carl


[1] https://docs.djangoproject.com/en/1.7/ref/signals/#class-prepared

Some Developer

unread,
Nov 5, 2014, 2:55:43 PM11/5/14
to django...@googlegroups.com
Cool. Thanks for the advice. I'll give it a go using the first template
tag syntax and see what happens. I've never written a template tag
library myself before so this will be a bit of a learning experience for me.
Reply all
Reply to author
Forward
0 new messages