##// END OF EJS Templates
Use more efficient way to get last replies
neko259 -
r986:68e7bfc6 default
parent child Browse files
Show More
@@ -1,185 +1,185 b''
1 1 import logging
2 2
3 3 from django.db.models import Count, Sum
4 4 from django.utils import timezone
5 5 from django.db import models
6 6
7 7 from boards import settings
8 8 from boards.utils import cached_result
9 9 from boards.models.post import Post
10 10
11 11
12 12 __author__ = 'neko259'
13 13
14 14
15 15 logger = logging.getLogger(__name__)
16 16
17 17
18 18 class ThreadManager(models.Manager):
19 19 def process_oldest_threads(self):
20 20 """
21 21 Preserves maximum thread count. If there are too many threads,
22 22 archive or delete the old ones.
23 23 """
24 24
25 25 threads = Thread.objects.filter(archived=False).order_by('-bump_time')
26 26 thread_count = threads.count()
27 27
28 28 if thread_count > settings.MAX_THREAD_COUNT:
29 29 num_threads_to_delete = thread_count - settings.MAX_THREAD_COUNT
30 30 old_threads = threads[thread_count - num_threads_to_delete:]
31 31
32 32 for thread in old_threads:
33 33 if settings.ARCHIVE_THREADS:
34 34 self._archive_thread(thread)
35 35 else:
36 36 thread.delete()
37 37
38 38 logger.info('Processed %d old threads' % num_threads_to_delete)
39 39
40 40 def _archive_thread(self, thread):
41 41 thread.archived = True
42 42 thread.bumpable = False
43 43 thread.last_edit_time = timezone.now()
44 44 thread.save(update_fields=['archived', 'last_edit_time', 'bumpable'])
45 45
46 46
47 47 class Thread(models.Model):
48 48 objects = ThreadManager()
49 49
50 50 class Meta:
51 51 app_label = 'boards'
52 52
53 53 tags = models.ManyToManyField('Tag')
54 54 bump_time = models.DateTimeField(db_index=True)
55 55 last_edit_time = models.DateTimeField()
56 56 archived = models.BooleanField(default=False)
57 57 bumpable = models.BooleanField(default=True)
58 58
59 59 def get_tags(self):
60 60 """
61 61 Gets a sorted tag list.
62 62 """
63 63
64 64 return self.tags.order_by('name')
65 65
66 66 def bump(self):
67 67 """
68 68 Bumps (moves to up) thread if possible.
69 69 """
70 70
71 71 if self.can_bump():
72 72 self.bump_time = timezone.now()
73 73
74 74 if self.get_reply_count() >= settings.MAX_POSTS_PER_THREAD:
75 75 self.bumpable = False
76 76
77 77 logger.info('Bumped thread %d' % self.id)
78 78
79 79 def get_reply_count(self):
80 80 return self.get_replies().count()
81 81
82 82 def get_images_count(self):
83 83 return self.get_replies().annotate(images_count=Count(
84 84 'images')).aggregate(Sum('images_count'))['images_count__sum']
85 85
86 86 def can_bump(self):
87 87 """
88 88 Checks if the thread can be bumped by replying to it.
89 89 """
90 90
91 91 return self.bumpable
92 92
93 93 def get_last_replies(self):
94 94 """
95 95 Gets several last replies, not including opening post
96 96 """
97 97
98 98 if settings.LAST_REPLIES_COUNT > 0:
99 99 reply_count = self.get_reply_count()
100 100
101 101 if reply_count > 0:
102 102 reply_count_to_show = min(settings.LAST_REPLIES_COUNT,
103 103 reply_count - 1)
104 104 replies = self.get_replies()
105 last_replies = replies[reply_count - reply_count_to_show:]
105 last_replies = replies.reverse()[:reply_count_to_show]
106 106
107 107 return last_replies
108 108
109 109 def get_skipped_replies_count(self):
110 110 """
111 111 Gets number of posts between opening post and last replies.
112 112 """
113 113 reply_count = self.get_reply_count()
114 114 last_replies_count = min(settings.LAST_REPLIES_COUNT,
115 115 reply_count - 1)
116 116 return reply_count - last_replies_count - 1
117 117
118 118 def get_replies(self, view_fields_only=False):
119 119 """
120 120 Gets sorted thread posts
121 121 """
122 122
123 123 query = Post.objects.filter(threads__in=[self])
124 124 query = query.order_by('pub_time').prefetch_related('images', 'thread', 'threads')
125 125 if view_fields_only:
126 126 query = query.defer('poster_user_agent')
127 127 return query.all()
128 128
129 129 def get_replies_with_images(self, view_fields_only=False):
130 130 """
131 131 Gets replies that have at least one image attached
132 132 """
133 133
134 134 return self.get_replies(view_fields_only).annotate(images_count=Count(
135 135 'images')).filter(images_count__gt=0)
136 136
137 137 def add_tag(self, tag):
138 138 """
139 139 Connects thread to a tag and tag to a thread
140 140 """
141 141
142 142 self.tags.add(tag)
143 143
144 144 def get_opening_post(self, only_id=False):
145 145 """
146 146 Gets the first post of the thread
147 147 """
148 148
149 149 query = self.get_replies().order_by('pub_time')
150 150 if only_id:
151 151 query = query.only('id')
152 152 opening_post = query.first()
153 153
154 154 return opening_post
155 155
156 156 @cached_result
157 157 def get_opening_post_id(self):
158 158 """
159 159 Gets ID of the first thread post.
160 160 """
161 161
162 162 return self.get_opening_post(only_id=True).id
163 163
164 164 def __unicode__(self):
165 165 return str(self.id)
166 166
167 167 def get_pub_time(self):
168 168 """
169 169 Gets opening post's pub time because thread does not have its own one.
170 170 """
171 171
172 172 return self.get_opening_post().pub_time
173 173
174 174 def delete(self, using=None):
175 175 """
176 176 Deletes thread with all replies.
177 177 """
178 178
179 179 for reply in self.get_replies().all():
180 180 reply.delete()
181 181
182 182 super(Thread, self).delete(using)
183 183
184 184 def __str__(self):
185 185 return 'T#{}/{}'.format(self.id, self.get_opening_post_id())
General Comments 0
You need to be logged in to leave comments. Login now