##// END OF EJS Templates
Don't return posts with the same image in random view
neko259 -
r1249:93f2906a default
parent child Browse files
Show More
@@ -1,110 +1,120 b''
1 import hashlib
1 import hashlib
2 import os
2 import os
3 from random import random
3 from random import random
4 import time
4 import time
5
5 from django.db import models
6 from django.db import models
6 from django.template.defaultfilters import filesizeformat
7 from django.template.defaultfilters import filesizeformat
8
7 from boards import thumbs
9 from boards import thumbs
10 import boards
8 from boards.models.base import Viewable
11 from boards.models.base import Viewable
9
12
10 __author__ = 'neko259'
13 __author__ = 'neko259'
11
14
12
15
13 IMAGE_THUMB_SIZE = (200, 150)
16 IMAGE_THUMB_SIZE = (200, 150)
14 IMAGES_DIRECTORY = 'images/'
17 IMAGES_DIRECTORY = 'images/'
15 FILE_EXTENSION_DELIMITER = '.'
18 FILE_EXTENSION_DELIMITER = '.'
16 HASH_LENGTH = 36
19 HASH_LENGTH = 36
17
20
18 CSS_CLASS_IMAGE = 'image'
21 CSS_CLASS_IMAGE = 'image'
19 CSS_CLASS_THUMB = 'thumb'
22 CSS_CLASS_THUMB = 'thumb'
20
23
21
24
22 class PostImageManager(models.Manager):
25 class PostImageManager(models.Manager):
23 def create_with_hash(self, image):
26 def create_with_hash(self, image):
24 image_hash = self.get_hash(image)
27 image_hash = self.get_hash(image)
25 existing = self.filter(hash=image_hash)
28 existing = self.filter(hash=image_hash)
26 if len(existing) > 0:
29 if len(existing) > 0:
27 post_image = existing[0]
30 post_image = existing[0]
28 else:
31 else:
29 post_image = PostImage.objects.create(image=image)
32 post_image = PostImage.objects.create(image=image)
30
33
31 return post_image
34 return post_image
32
35
33 def get_hash(self, image):
36 def get_hash(self, image):
34 """
37 """
35 Gets hash of an image.
38 Gets hash of an image.
36 """
39 """
37 md5 = hashlib.md5()
40 md5 = hashlib.md5()
38 for chunk in image.chunks():
41 for chunk in image.chunks():
39 md5.update(chunk)
42 md5.update(chunk)
40 return md5.hexdigest()
43 return md5.hexdigest()
41
44
45 def get_random_images(self, count):
46 return self.order_by('?')[:count]
47
42
48
43 class PostImage(models.Model, Viewable):
49 class PostImage(models.Model, Viewable):
44 objects = PostImageManager()
50 objects = PostImageManager()
45
51
46 class Meta:
52 class Meta:
47 app_label = 'boards'
53 app_label = 'boards'
48 ordering = ('id',)
54 ordering = ('id',)
49
55
50 def _update_image_filename(self, filename):
56 def _update_image_filename(self, filename):
51 """
57 """
52 Gets unique image filename
58 Gets unique image filename
53 """
59 """
54
60
55 path = IMAGES_DIRECTORY
61 path = IMAGES_DIRECTORY
56
62
57 # TODO Use something other than random number in file name
63 # TODO Use something other than random number in file name
58 new_name = '{}{}.{}'.format(
64 new_name = '{}{}.{}'.format(
59 str(int(time.mktime(time.gmtime()))),
65 str(int(time.mktime(time.gmtime()))),
60 str(int(random() * 1000)),
66 str(int(random() * 1000)),
61 filename.split(FILE_EXTENSION_DELIMITER)[-1:][0])
67 filename.split(FILE_EXTENSION_DELIMITER)[-1:][0])
62
68
63 return os.path.join(path, new_name)
69 return os.path.join(path, new_name)
64
70
65 width = models.IntegerField(default=0)
71 width = models.IntegerField(default=0)
66 height = models.IntegerField(default=0)
72 height = models.IntegerField(default=0)
67
73
68 pre_width = models.IntegerField(default=0)
74 pre_width = models.IntegerField(default=0)
69 pre_height = models.IntegerField(default=0)
75 pre_height = models.IntegerField(default=0)
70
76
71 image = thumbs.ImageWithThumbsField(upload_to=_update_image_filename,
77 image = thumbs.ImageWithThumbsField(upload_to=_update_image_filename,
72 blank=True, sizes=(IMAGE_THUMB_SIZE,),
78 blank=True, sizes=(IMAGE_THUMB_SIZE,),
73 width_field='width',
79 width_field='width',
74 height_field='height',
80 height_field='height',
75 preview_width_field='pre_width',
81 preview_width_field='pre_width',
76 preview_height_field='pre_height')
82 preview_height_field='pre_height')
77 hash = models.CharField(max_length=HASH_LENGTH)
83 hash = models.CharField(max_length=HASH_LENGTH)
78
84
79 def save(self, *args, **kwargs):
85 def save(self, *args, **kwargs):
80 """
86 """
81 Saves the model and computes the image hash for deduplication purposes.
87 Saves the model and computes the image hash for deduplication purposes.
82 """
88 """
83
89
84 if not self.pk and self.image:
90 if not self.pk and self.image:
85 self.hash = PostImage.objects.get_hash(self.image)
91 self.hash = PostImage.objects.get_hash(self.image)
86 super(PostImage, self).save(*args, **kwargs)
92 super(PostImage, self).save(*args, **kwargs)
87
93
88 def __str__(self):
94 def __str__(self):
89 return self.image.url
95 return self.image.url
90
96
91 def get_view(self):
97 def get_view(self):
92 metadata = '{}, {}'.format(self.image.name.split('.')[-1],
98 metadata = '{}, {}'.format(self.image.name.split('.')[-1],
93 filesizeformat(self.image.size))
99 filesizeformat(self.image.size))
94 return '<div class="{}">' \
100 return '<div class="{}">' \
95 '<a class="{}" href="{full}">' \
101 '<a class="{}" href="{full}">' \
96 '<img class="post-image-preview"' \
102 '<img class="post-image-preview"' \
97 ' src="{}"' \
103 ' src="{}"' \
98 ' alt="{}"' \
104 ' alt="{}"' \
99 ' width="{}"' \
105 ' width="{}"' \
100 ' height="{}"' \
106 ' height="{}"' \
101 ' data-width="{}"' \
107 ' data-width="{}"' \
102 ' data-height="{}" />' \
108 ' data-height="{}" />' \
103 '</a>' \
109 '</a>' \
104 '<div class="image-metadata">{image_meta}</div>' \
110 '<div class="image-metadata">{image_meta}</div>' \
105 '</div>'\
111 '</div>'\
106 .format(CSS_CLASS_IMAGE, CSS_CLASS_THUMB,
112 .format(CSS_CLASS_IMAGE, CSS_CLASS_THUMB,
107 self.image.url_200x150,
113 self.image.url_200x150,
108 str(self.hash), str(self.pre_width),
114 str(self.hash), str(self.pre_width),
109 str(self.pre_height), str(self.width), str(self.height),
115 str(self.pre_height), str(self.width), str(self.height),
110 full=self.image.url, image_meta=metadata)
116 full=self.image.url, image_meta=metadata)
117
118 def get_random_associated_post(self):
119 return boards.models.Post.objects.filter(images__in=[self])\
120 .order_by('?').first()
@@ -1,32 +1,32 b''
1 {% extends "boards/base.html" %}
1 {% extends "boards/base.html" %}
2
2
3 {% load i18n %}
3 {% load i18n %}
4
4
5 {% block head %}
5 {% block head %}
6 <title>{% trans 'Random images' %} - {{ site_name }}</title>
6 <title>{% trans 'Random images' %} - {{ site_name }}</title>
7 {% endblock %}
7 {% endblock %}
8
8
9 {% block content %}
9 {% block content %}
10
10
11 {% if posts %}
11 {% if images %}
12 <div class="random-images-table">
12 <div class="random-images-table">
13 <div>
13 <div>
14 {% for post in posts %}
14 {% for image in images %}
15 <div class="gallery_image">
15 <div class="gallery_image">
16 {% with post.get_first_image as image %}
17 {% autoescape off %}
16 {% autoescape off %}
18 {{ image.get_view }}
17 {{ image.get_view }}
19 {% endautoescape %}
18 {% endautoescape %}
19 {% with image.get_random_associated_post as post %}
20 <a href="{{ post.get_absolute_url }}">>>{{ post.id }}</a>
20 <a href="{{ post.get_absolute_url }}">>>{{ post.id }}</a>
21 {% endwith %}
21 {% endwith %}
22 </div>
22 </div>
23 {% if forloop.counter|divisibleby:"3" %}
23 {% if forloop.counter|divisibleby:"3" %}
24 </div>
24 </div>
25 <div>
25 <div>
26 {% endif %}
26 {% endif %}
27 {% endfor %}
27 {% endfor %}
28 </div>
28 </div>
29 </div>
29 </div>
30 {% endif %}
30 {% endif %}
31
31
32 {% endblock %}
32 {% endblock %}
@@ -1,28 +1,22 b''
1 from django.shortcuts import render
1 from django.shortcuts import render
2 from django.template import RequestContext
3 from django.views.generic import View
2 from django.views.generic import View
4 from django.db.models import Count
5
3
6 from boards.models import Post
4 from boards.models import PostImage
7 from boards.mdx_neboard import Parser
8
5
9 __author__ = 'neko259'
6 __author__ = 'neko259'
10
7
11 TEMPLATE = 'boards/random.html'
8 TEMPLATE = 'boards/random.html'
12
9
13 CONTEXT_POSTS = 'posts'
10 CONTEXT_IMAGES = 'images'
14
11
15 RANDOM_POST_COUNT = 9
12 RANDOM_POST_COUNT = 9
16
13
17
14
18 class RandomImageView(View):
15 class RandomImageView(View):
19 def get(self, request):
16 def get(self, request):
20 params = dict()
17 params = dict()
21
18
22 posts = Post.objects.annotate(images_count=Count(
19 params[CONTEXT_IMAGES] = PostImage.objects.get_random_images(
23 'images')).filter(images_count__gt=0).order_by('?')\
20 RANDOM_POST_COUNT)
24 [:RANDOM_POST_COUNT]
25
26 params[CONTEXT_POSTS] = posts
27
21
28 return render(request, TEMPLATE, params)
22 return render(request, TEMPLATE, params)
General Comments 0
You need to be logged in to leave comments. Login now