views:

71

answers:

3

Ok, imagine a typical scenario, - there is a thread object and comments, attached to it. It can be expressed in django ORM's terms very roughly like this:

class Thread(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=255)

class Comment(models.Model):
    id = models.AutoField(primary_key=True)
    content = models.TextField()
    created = models.DateTimeField(editable=False)
    thread = models.ForeignKey(Thread, related_name='comments')

    def save(self, force_insert=False, force_update=False):
        self.created = datetime.datetime.now()
        super(Comment, self).save(force_insert, force_delete)

So, when displaying the actual data, the comments are going to be ordered by their creation time (since I like not to make an assumption, that an identity field also guarantees you the correct order of the records).

But what if I needed to be able to control (and alter) the order in which the comments must appear within a thread and to be able to move comments from one thread to another.

This could be accomplished by adding, for example, a "sequence" field to the comment model and restricting the uniqueness of the combination of the "sequence" field and "thread" field of the comment model (so that there can be no comments within a thread with the same sequence number). A unique key on these fields should be sufficient (in terms of django, it can be accomplished via unique_together, I think).

However, this adds a computational (and coding :P) overhead, because if you are to change the order of the comments, by changing their sequence numbers, you must also update the comments with sequence numbers, higher, than the target comment's sequence number. And so on. It is just asking for trouble.

Somehow, I just can't get my head around this. Maybe I am just missing something?

(If it is possible, don't regard this as a django-only problem. IMO it is language-agnostic-ish, since it has nothing django-specific about it, when you think of it)

EDIT: I've suddenly realized, that there is no actual question in the, err, question. So the question is, what would be the most lightweight way to implement a such a model, besides the obvious way I've described (seems too cumbersome to me).

+2  A: 

If you specify an ordering attribute for the Comment class, that order will be respected wherever Comments are displayed.

class Comment(models.Model):
    id = models.AutoField(primary_key=True)
    content = models.TextField()
    created = models.DateTimeField(editable=False)
    thread = models.ForeignKey(Thread, related_name='comments')

    class Meta:
        ordering = ('-created')

    def save(self, force_insert=False, force_update=False):
        self.created = datetime.datetime.now()
        super(Comment, self).save(force_insert, force_delete)

The docs are here.

If you move a comment from thread A to thread B, because of the ordering specified it will be still displaying in the right order of creation...

But maybe I misunderstood your question...


Edit: OK, so your question really boils down to:

"But what if I needed to be able to control (and alter) the order in which the comments must appear within a thread and to be able to move comments from one thread to another."

I don't think you are going to find a mechanism other than what you mention: an ordinal on the Comment class.

And, yes, when you move a comment from thread to thread, you will have to have some logic to reorder things if necessary.

If that is indeed your requirement, I don't see any mechanisms to make your life easier - sorry.

celopes
No, I was asking about imposing an arbitrary order on the comments within a thread, ordering them by creation time, for example, is indeed trivial (as illustrated by your implementation)
shylent
+1  A: 

If I understand your question (not entirely sure I do), you want to create and maintain an arbitrary ordering of Comments relative to a Thread.

The only ways I know of doing this is to either have an ordering field in the Comment, or a list-of-Comment-ids-in-order field in the Thread, or possibly a separate table that has a (Thread-id, Comment-id, order) tuple in it.

For a website I did about 2 years ago we went with the middle option for a Newsletter which contained 10-30 articles. I used some jQuery magic on the Newsletter's admin page and it let the admins shuffle the Article titles around while in the background it kept updating the Article-ids-in-order field of the Newsletter.

Peter Rowell
You understand it perfectly right. I like the idea of "article-ids-in-order" field, however hackish it can be (keeping multiple values in a single field certainly does seem hackish to me). Still a great idea! It is surely something I should try first, before resorting to a method I was going to use (the one described in my actual question).
shylent
@shylent: I pasted a slightly tweaked copy (added some comments): http://pastebin.com/m568bc926 . Let me know if you have questions/problems. [email protected]
Peter Rowell
A: 

An alternative approach is to use a floating point number as the ordering field. That way, if you want to put a comment in the middle of the thread, you just compute the average value of the previous comment and the next one, and use it for the ordering field of the comment you're inserting. There's of course a limit to how much times you can do division on a floating point before you start getting the same values, but that can easily be solved by periodically multiplying all the order fields by i.e. 2.

gooli