~chipaca/unity-lens-video/custom-user-agent

« back to all changes in this revision

Viewing changes to oneliners/models.py

  • Committer: Janos Gyerik
  • Date: 2012-04-04 13:22:47 UTC
  • Revision ID: burlyman@titan2x.com-20120404132247-2s7liq2i4e7nn8ul
minor improvement to create_user_profile signal

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
from django.db import models
2
 
from django.db.models import Count
3
 
from django.contrib.auth.models import User as DjangoUser
4
 
from django.contrib.auth.models import UserManager
 
2
from django.db.models import Count, Q
 
3
from django.db.models.signals import post_save
 
4
from django.contrib.auth.models import User
 
5
from django.contrib.comments.models import Comment
 
6
from django.dispatch import receiver
5
7
 
6
8
from datetime import datetime
7
 
import random, string, re
 
9
import random
 
10
import string
 
11
import re
 
12
 
 
13
''' Constants '''
 
14
 
 
15
RECENT_LIMIT = 25
 
16
SEARCH_LIMIT = 25
 
17
FEED_LIMIT = 10
8
18
 
9
19
 
10
20
''' Helper methods '''
11
21
 
 
22
 
12
23
def randomstring(length=16):
13
24
    return ''.join(random.choice(string.letters) for i in xrange(length))
14
25
 
15
26
 
 
27
def get_query_terms(query):
 
28
    if query is None:
 
29
        return ()
 
30
 
 
31
    query = query.strip()
 
32
    if query == '':
 
33
        return ()
 
34
 
 
35
    return re.split(r' +', query)
 
36
 
 
37
 
 
38
@receiver(post_save, sender=User)
 
39
def create_user_profile(sender, instance, created, **kwargs):
 
40
    if created:
 
41
        try:
 
42
            HackerProfile.objects.get_or_create(user=instance)
 
43
        except:
 
44
            pass
 
45
 
 
46
post_save.connect(create_user_profile, sender=User)
 
47
 
16
48
''' Core models '''
17
49
 
18
 
class Hacker(DjangoUser):
19
 
    twitter = models.SlugField(max_length=100, blank=True, null=True)
20
 
    #stackoverflow
21
 
    #blog
22
 
    #homepage
23
 
 
24
 
    # Use UserManager to get the create_user method, etc.
25
 
    objects = UserManager()
 
50
 
 
51
class HackerProfile(models.Model):
 
52
    user = models.OneToOneField(User)
 
53
 
 
54
    display_name = models.SlugField(max_length=50, blank=True, null=True, unique=True)
 
55
    twitter_name = models.SlugField(max_length=50, blank=True, null=True)
 
56
    blog_url = models.URLField('Blog URL', blank=True, null=True)
 
57
    homepage_url = models.URLField('Homepage URL', blank=True, null=True)
 
58
 
 
59
    def twitter_url(self):
 
60
        return 'http://twitter.com/%s/' % self.twitter_name
 
61
 
 
62
    def get_username(self):
 
63
        return self.user.username
 
64
 
 
65
    def get_email(self):
 
66
        return self.user.email
 
67
 
 
68
    def get_date_joined(self):
 
69
        return self.user.date_joined
 
70
 
 
71
    def get_display_name(self):
 
72
        return self.display_name or self.user.username
 
73
 
 
74
    def __unicode__(self):
 
75
        return ', '.join([x for x in (self.user.username, self.user.email) if x])
 
76
 
 
77
    class Meta:
 
78
        ordering = ('-id',)
26
79
 
27
80
 
28
81
class OneLiner(models.Model):
29
 
    hacker = models.ForeignKey(Hacker)
 
82
    user = models.ForeignKey(User)
30
83
 
 
84
    summary = models.CharField(max_length=200)
31
85
    line = models.TextField()
32
 
    summary = models.TextField()
33
 
    explanation = models.TextField(blank=True)
34
 
    caveats = models.TextField(blank=True)
 
86
    explanation = models.TextField()
 
87
    limitations = models.TextField(blank=True)
35
88
 
36
 
    is_published = models.BooleanField(default=False)
 
89
    is_published = models.BooleanField(default=True)
 
90
    was_tweeted = models.BooleanField(default=False)
37
91
 
38
92
    created_dt = models.DateTimeField(default=datetime.now, blank=True)
39
93
 
40
 
    def lines(self):
41
 
        return [x for x in self.line.split('\n') if x.strip() != '']
42
 
 
43
 
    def vote_up(self, hacker):
44
 
        Vote.vote_up(hacker, self)
45
 
 
46
 
    def vote_down(self, hacker):
47
 
        Vote.vote_down(hacker, self)
 
94
    def vote_up(self, user):
 
95
        Vote.vote_up(user, self)
 
96
 
 
97
    def vote_down(self, user):
 
98
        Vote.vote_down(user, self)
48
99
 
49
100
    def get_votes(self):
50
 
        return (self.get_votes_up(), self.get_votes_down())
 
101
        return (self.get_votes_up(), self.get_votes_down())
51
102
 
52
103
    def get_votes_up(self):
53
 
        return self.vote_set.filter(up=True).count()
 
104
        return self.vote_set.filter(up=True).count()
54
105
 
55
106
    def get_votes_down(self):
56
 
        return self.vote_set.filter(up=False).count()
57
 
 
58
 
    @staticmethod
59
 
    def top(limit=50):
60
 
        return OneLiner.objects.filter(vote__up=True).annotate(votes=Count('vote')).order_by('-votes')[:limit]
61
 
 
62
 
    def __unicode__(self):
63
 
        return self.summary
64
 
 
65
 
    class Meta:
66
 
        get_latest_by = 'pk'
 
107
        return self.vote_set.filter(up=False).count()
 
108
 
 
109
    def questions(self):
 
110
        return self.answer_set.filter(question__is_published=True)
 
111
 
 
112
    def alternatives(self):
 
113
        return self.alternativeoneliner_set.filter(alternative__is_published=True)
 
114
 
 
115
    def add_alternative(self, alternative):
 
116
        AlternativeOneLiner(alternative=alternative, oneliner=self).save()
 
117
 
 
118
    def relateds(self):
 
119
        return self.related_set.filter(oneliner__is_published=True)
 
120
 
 
121
    @staticmethod
 
122
    def get(pk):
 
123
        return OneLiner.objects.get(pk=pk)
 
124
 
 
125
    @staticmethod
 
126
    def feed(limit=FEED_LIMIT):
 
127
        return OneLiner.recent(limit)
 
128
 
 
129
    @staticmethod
 
130
    def recent(limit=RECENT_LIMIT):
 
131
        return OneLiner.objects.filter(is_published=True)[:limit]
 
132
 
 
133
    @staticmethod
 
134
    def recent_by_tag(text, limit=RECENT_LIMIT):
 
135
        return OneLiner.objects.filter(is_published=True, onelinertag__tag__text=text)[:limit]
 
136
 
 
137
    @staticmethod
 
138
    def top(limit=SEARCH_LIMIT):
 
139
        return OneLiner.objects.filter(vote__up=True).annotate(votes=Count('vote')).order_by('-votes')[:limit]
 
140
 
 
141
    @staticmethod
 
142
    def simplesearch(query=None, limit=SEARCH_LIMIT):
 
143
        qq = Q()
 
144
        for term in get_query_terms(query):
 
145
            sub_qq = Q()
 
146
            sub_qq |= Q(summary__icontains=term)
 
147
            sub_qq |= Q(line__icontains=term)
 
148
            sub_qq |= Q(explanation__icontains=term)
 
149
            sub_qq |= Q(limitations__icontains=term)
 
150
            qq &= Q(sub_qq)
 
151
        return OneLiner.objects.filter(is_published=True).filter(qq)[:limit]
 
152
 
 
153
    @staticmethod
 
154
    def search(form, limit=SEARCH_LIMIT):
 
155
        query = form.cleaned_data.get('query')
 
156
        match_summary = form.cleaned_data.get('match_summary')
 
157
        match_line = form.cleaned_data.get('match_line')
 
158
        match_explanation = form.cleaned_data.get('match_explanation')
 
159
        match_limitations = form.cleaned_data.get('match_limitations')
 
160
        match_whole_words = form.cleaned_data.get('match_whole_words')
 
161
 
 
162
        terms = get_query_terms(query)
 
163
        qq = Q()
 
164
        for term in terms:
 
165
            sub_qq = Q()
 
166
            if match_summary:
 
167
                sub_qq |= Q(summary__icontains=term)
 
168
            if match_line:
 
169
                sub_qq |= Q(line__icontains=term)
 
170
            if match_explanation:
 
171
                sub_qq |= Q(explanation__icontains=term)
 
172
            if match_limitations:
 
173
                sub_qq |= Q(limitations__icontains=term)
 
174
            if len(sub_qq.children) > 0:
 
175
                qq &= Q(sub_qq)
 
176
 
 
177
        if len(qq.children) > 0:
 
178
            results = OneLiner.objects.filter(is_published=True).filter(qq)
 
179
 
 
180
            if match_whole_words:
 
181
                results = [x for x in results if x.matches_words(terms, match_summary, match_line, match_explanation, match_limitations)]
 
182
 
 
183
            return results[:limit]
 
184
        else:
 
185
            return ()
 
186
 
 
187
    def matches_words(self, terms, match_summary, match_line, match_explanation, match_limitations):
 
188
        for term in terms:
 
189
            if match_summary and re.search(r'\b%s\b' % term, self.summary):
 
190
                return True
 
191
            if match_line and re.search(r'\b%s\b' % term, self.line):
 
192
                return True
 
193
            if match_explanation and re.search(r'\b%s\b' % term, self.explanation):
 
194
                return True
 
195
            if match_limitations and re.search(r'\b%s\b' % term, self.limitations):
 
196
                return True
 
197
 
 
198
    def update_tags(self):
 
199
        self.onelinertag_set.all().delete()
 
200
        if self.is_published:
 
201
            words = re.split(r'[ ;|]+', self.line)
 
202
            tagwords = set([word for word in words if re.match(r'^[a-z_]{2,}$', word)])
 
203
            for tagword in tagwords:
 
204
                tag = Tag.create_or_get(tagword)
 
205
                OneLinerTag(oneliner=self, tag=tag).save()
 
206
 
 
207
    def get_tags(self):
 
208
        return [rel.tag.text for rel in self.onelinertag_set.all()]
 
209
 
 
210
    def save(self, *args, **kwargs):
 
211
        ret = super(OneLiner, self).save(*args, **kwargs)
 
212
        self.update_tags()
 
213
        return ret
 
214
 
 
215
    def get_absolute_url(self):
 
216
        return "/main/oneliner/%i/" % self.pk
 
217
 
 
218
    def __unicode__(self):
 
219
        return self.summary
 
220
 
 
221
    class Meta:
 
222
        get_latest_by = 'pk'
 
223
        ordering = ('-id',)
 
224
 
 
225
 
 
226
class AlternativeOneLiner(models.Model):
 
227
    alternative = models.ForeignKey(OneLiner, related_name='related_set')
 
228
    oneliner = models.ForeignKey(OneLiner)
 
229
 
 
230
    class Meta:
 
231
        unique_together = (('alternative', 'oneliner',),)
 
232
 
 
233
 
 
234
class Tag(models.Model):
 
235
    text = models.SlugField(max_length=50)
 
236
 
 
237
    def __unicode__(self):
 
238
        return self.text
 
239
 
 
240
    @staticmethod
 
241
    def create_or_get(text):
 
242
        try:
 
243
            return Tag.objects.get(text=text)
 
244
        except:
 
245
            tag = Tag(text=text)
 
246
            tag.save()
 
247
            return tag
 
248
 
 
249
    @staticmethod
 
250
    def tagcloud():
 
251
        return Tag.objects.annotate(count=Count('onelinertag')).filter(count__gt=1).order_by('-count').values('text', 'count')
 
252
        #return Tag.objects.annotate(count=Count('onelinertag')).order_by('-count').values_list('text', 'count')
 
253
 
 
254
 
 
255
class OneLinerTag(models.Model):
 
256
    oneliner = models.ForeignKey(OneLiner)
 
257
    tag = models.ForeignKey(Tag)
 
258
 
 
259
 
 
260
class Question(models.Model):
 
261
    user = models.ForeignKey(User)
 
262
    summary = models.CharField(max_length=200)
 
263
    explanation = models.TextField(blank=True, null=True)
 
264
    is_published = models.BooleanField(default=True)
 
265
    is_answered = models.BooleanField(default=False)
 
266
    created_dt = models.DateTimeField(default=datetime.now, blank=True)
 
267
 
 
268
    def __unicode__(self):
 
269
        return self.summary
 
270
 
 
271
    def add_answer(self, oneliner):
 
272
        Answer(question=self, oneliner=oneliner).save()
 
273
 
 
274
    def oneliners(self):
 
275
        return self.answer_set.filter(oneliner__is_published=True)
 
276
 
 
277
    def accept_answer(self, oneliner):
 
278
        self.is_answered = True
 
279
        self.save()
 
280
        try:
 
281
            AcceptedAnswer(question=self, oneliner=oneliner).save()
 
282
        except:
 
283
            pass
 
284
 
 
285
    def clear_all_answers(self):
 
286
        self.is_answered = False
 
287
        self.save()
 
288
 
 
289
    def save(self, *args, **kwargs):
 
290
        if not self.is_answered:
 
291
            AcceptedAnswer.objects.filter(question=self).delete()
 
292
        return super(Question, self).save(*args, **kwargs)
 
293
 
 
294
    @staticmethod
 
295
    def get(pk):
 
296
        return Question.objects.get(pk=pk)
 
297
 
 
298
    @staticmethod
 
299
    def feed(limit=FEED_LIMIT):
 
300
        return Question.objects.filter(is_published=True)[:limit]
 
301
 
 
302
    @staticmethod
 
303
    def recent(limit=RECENT_LIMIT):
 
304
        return Question.objects.filter(is_published=True).exclude(is_answered=True)[:limit]
 
305
 
 
306
    @staticmethod
 
307
    def latest():
 
308
        try:
 
309
            return Question.recent(1)[0]
 
310
        except:
 
311
            pass
 
312
 
 
313
    def get_absolute_url(self):
 
314
        return "/main/question/%i/" % self.pk
 
315
 
 
316
    class Meta:
 
317
        get_latest_by = 'pk'
 
318
        ordering = ('-id',)
 
319
 
 
320
 
 
321
class Answer(models.Model):
 
322
    question = models.ForeignKey(Question)
 
323
    oneliner = models.ForeignKey(OneLiner)
 
324
 
 
325
 
 
326
class AcceptedAnswer(models.Model):
 
327
    question = models.ForeignKey(Question)
 
328
    oneliner = models.ForeignKey(OneLiner)
 
329
 
 
330
    class Meta:
 
331
        unique_together = (('question', 'oneliner',),)
67
332
 
68
333
 
69
334
class Vote(models.Model):
70
 
    hacker = models.ForeignKey(Hacker)
 
335
    user = models.ForeignKey(User)
71
336
    oneliner = models.ForeignKey(OneLiner)
72
337
    up = models.BooleanField(default=True)
73
338
 
74
339
    created_dt = models.DateTimeField(default=datetime.now)
75
340
 
76
341
    @staticmethod
77
 
    def vote(hacker, oneliner, updown):
78
 
        if oneliner.hacker == hacker:
79
 
            return
80
 
 
81
 
        try:
82
 
            oneliner.vote_set.get(hacker=hacker, up=updown)
83
 
            return
84
 
        except:
85
 
            pass
86
 
 
87
 
        oneliner.vote_set.filter(hacker=hacker).delete()
88
 
        Vote(hacker=hacker, oneliner=oneliner, up=updown).save()
89
 
 
90
 
    @staticmethod
91
 
    def vote_up(hacker, oneliner):
92
 
        Vote.vote(hacker, oneliner, True)
93
 
 
94
 
    @staticmethod
95
 
    def vote_down(hacker, oneliner):
96
 
        Vote.vote(hacker, oneliner, False)
 
342
    def vote(user, oneliner, updown):
 
343
        if oneliner.user == user:
 
344
            return
 
345
 
 
346
        try:
 
347
            oneliner.vote_set.get(user=user, up=updown)
 
348
            return
 
349
        except:
 
350
            pass
 
351
 
 
352
        oneliner.vote_set.filter(user=user).delete()
 
353
        Vote(user=user, oneliner=oneliner, up=updown).save()
 
354
 
 
355
    @staticmethod
 
356
    def vote_up(user, oneliner):
 
357
        Vote.vote(user, oneliner, True)
 
358
 
 
359
    @staticmethod
 
360
    def vote_down(user, oneliner):
 
361
        Vote.vote(user, oneliner, False)
97
362
 
98
363
    def __unicode__(self):
99
 
        return '%s %s %s' % (self.hacker.full_name, ('--', '++')[self.up], self.oneliner.summary)
 
364
        return '%s %s %s' % (self.user.full_name, ('--', '++')[self.up], self.oneliner.summary)
100
365
 
101
366
    class Meta:
102
 
        unique_together = (('hacker', 'oneliner',),)
 
367
        unique_together = (('user', 'oneliner',),)
 
368
 
 
369
 
 
370
def Comment_recent(limit=RECENT_LIMIT):
 
371
    return Comment.objects.filter(is_public=True).exclude(is_removed=True).order_by('-submit_date')[:limit]
 
372
 
 
373
 
 
374
def Comment_feed(limit=FEED_LIMIT):
 
375
    return Comment_recent(limit)
103
376
 
104
377
 
105
378
# eof