# HG changeset patch # User neko259 # Date 2013-09-11 18:14:23 # Node ID 4857f1068eff63298299ccb7c92609e114ddae76 # Parent 7c1533629b6282d985753770da3a21cd13b3a33b Added replies manytomany field to the post to get its replies more efficiently. diff --git a/boards/migrations/0005_auto.py b/boards/migrations/0005_auto.py new file mode 100644 --- /dev/null +++ b/boards/migrations/0005_auto.py @@ -0,0 +1,81 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models +from boards.models import Post, NO_PARENT + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding M2M table for field replies on 'Post' + m2m_table_name = db.shorten_name(u'boards_post_replies') + db.create_table(m2m_table_name, ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('from_post', models.ForeignKey(orm[u'boards.post'], null=False)), + ('to_post', models.ForeignKey(orm[u'boards.post'], null=False)) + )) + db.create_unique(m2m_table_name, ['from_post_id', 'to_post_id']) + + for post in Post.objects.all(): + if post.parent != NO_PARENT: + parent = Post.objects.get(id=post.parent) + parent.replies.add(post) + + + def backwards(self, orm): + # Removing M2M table for field replies on 'Post' + db.delete_table(db.shorten_name(u'boards_post_replies')) + + + models = { + u'boards.ban': { + 'Meta': {'object_name': 'Ban'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}) + }, + u'boards.post': { + 'Meta': {'object_name': 'Post'}, + '_text_rendered': ('django.db.models.fields.TextField', [], {}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), + 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), + 'parent': ('django.db.models.fields.BigIntegerField', [], {}), + 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), + 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), + 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), + 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'re+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}), + 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['boards.Tag']", 'symmetrical': 'False'}), + 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), + 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['boards.User']", 'null': 'True'}) + }, + u'boards.setting': { + 'Meta': {'object_name': 'Setting'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['boards.User']"}), + 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'boards.tag': { + 'Meta': {'object_name': 'Tag'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'boards.user': { + 'Meta': {'object_name': 'User'}, + 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), + 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_access_time': ('django.db.models.fields.DateTimeField', [], {}), + 'rank': ('django.db.models.fields.IntegerField', [], {}), + 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), + 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + } + } + + complete_apps = ['boards'] \ No newline at end of file diff --git a/boards/models.py b/boards/models.py --- a/boards/models.py +++ b/boards/models.py @@ -5,10 +5,10 @@ import time import math from django.db import models +from django.db.models import Count from django.http import Http404 from django.utils import timezone from markupfield.fields import MarkupField -from threading import Thread from neboard import settings import thumbs @@ -45,6 +45,10 @@ class PostManager(models.Manager): last_edit_time=timezone.now(), user=user) + if parent_id != NO_PARENT: + parent = self.get(id=parent_id) + parent.replies.add(post) + if tags: map(post.tags.add, tags) @@ -56,9 +60,8 @@ class PostManager(models.Manager): return post def delete_post(self, post): - children = self.filter(parent=post.id) - - map(self.delete_post, children) + if post.replies.count() > 0: + map(self.delete_post, post.replies) post.delete() def delete_posts_by_ip(self, ip): @@ -93,11 +96,9 @@ class PostManager(models.Manager): except Post.DoesNotExist: raise Http404 - if opening_post.parent == NO_PARENT: - replies = self.filter(parent=opening_post_id) - + if opening_post.replies: thread = [opening_post] - thread.extend(replies) + thread.extend(opening_post.replies.all()) return thread @@ -222,11 +223,17 @@ class Post(models.Model): poster_ip = models.GenericIPAddressField() poster_user_agent = models.TextField() + + # TODO Convert this field to ForeignKey parent = models.BigIntegerField() + tags = models.ManyToManyField(Tag) last_edit_time = models.DateTimeField() user = models.ForeignKey('User', null=True, default=None) + replies = models.ManyToManyField('Post', symmetrical=False, null=True, + blank=True, related_name='re+') + def __unicode__(self): return '#' + str(self.id) + ' ' + self.title + ' (' + \ self.text.raw[:50] + ')' @@ -239,16 +246,15 @@ class Post(models.Model): return title def _get_replies(self): - return Post.objects.filter(parent=self.id) + return self.replies def get_reply_count(self): - return self._get_replies().count() + return self.replies.count() def get_images_count(self): images_count = 1 if self.image else 0 - replies = self._get_replies() - for reply in replies: + for reply in self.replies: if reply.image: images_count += 1 @@ -257,9 +263,9 @@ class Post(models.Model): def can_bump(self): """Check if the thread can be bumped by replying""" - replies_count = self.get_reply_count() + 1 + post_count = self.get_reply_count() + 1 - return replies_count <= settings.MAX_POSTS_PER_THREAD + return post_count <= settings.MAX_POSTS_PER_THREAD def get_last_replies(self): if settings.LAST_REPLIES_COUNT > 0: @@ -268,8 +274,8 @@ class Post(models.Model): if reply_count > 0: reply_count_to_show = min(settings.LAST_REPLIES_COUNT, reply_count) - last_replies = self._get_replies()[reply_count - - reply_count_to_show:] + last_replies = self.replies.all()[reply_count - + reply_count_to_show:] return last_replies diff --git a/boards/views.py b/boards/views.py --- a/boards/views.py +++ b/boards/views.py @@ -219,6 +219,7 @@ def jump_to_post(request, post_id): if boards.models.NO_PARENT == post.parent: return redirect(thread, post_id=post.id) else: + # TODO Change this code to not use 'parent' field anymore parent_thread = get_object_or_404(Post, id=post.parent) return redirect(reverse(thread, kwargs={'post_id': parent_thread.id}) + '#' + str(post.id))