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