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 |
|
11 | {% if images %} | |
12 | <div class="random-images-table"> |
|
12 | <div class="random-images-table"> | |
13 | <div> |
|
13 | <div> | |
14 |
{% for |
|
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_ |
|
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