qraq
qraq

Reputation: 318

Loading tree of relations at once

I've got model called Post:

class Post(models.Model):
    poster = models.ForeignKey(User)
    content = models.TextField(verbose_name='Text', max_length=1000)
    reply_to = models.ForeignKey('self', null=True, blank=True, default=None)   

This allows to add 'first post' (with blank reply_to), and reply to post and even 'reply to reply'

For example I've got in my database something like that:

First Post
    Reply one
        Reply to reply one
    Reply two
        Reply to reply two

How to load that tree of replies?

When I use:

r = Post.objects.filter(reply_to=FirstPost)

It returns of course:

Reply one
Reply two

Is it possible to load all related posts at once? I need it mainly to count all replies to first post.

Upvotes: 0

Views: 136

Answers (2)

Martijn Pieters
Martijn Pieters

Reputation: 1123940

No, I don't think there is a way to load all replies at once.

But, you can add extra metadata to the post type to be able to run a in-order-style query, where counting the number of replies becomes a simple calculation with data already loaded for the parents node.

See this article on how you could do that (it uses the MySQL SQL dialect, and PHP, but the principles still apply).

Basically, you add left and right fields to the nodes in your tree that define an ordering, letting you easily count the number of items below a given root element in the tree. It's like a Binary Tree in a database table. The principle is taken from this excellent database design book: "Joe Celko's Trees and Hierarchies in SQL for Smarties".

Upvotes: 0

You can use MPTT (http://django-mptt.github.com/django-mptt/tutorial.html#the-problem). I have not used this library before so let me know how it goes.

models.py

class Post(MPTTModel):
    poster = models.ForeignKey(User)
    content = models.TextField(verbose_name='Text', max_length=1000)
    parent = models.TreeForeignKey('self', null=True, blank=True, related_name='children')
    class MPTTMeta:
        order_insertion_by = ['poster']

views.py

 ....
 r = FirstPost.get_children()

Upvotes: 4

Related Questions