| author | cavaliet |
| Wed, 10 Jul 2013 15:31:38 +0200 | |
| changeset 230 | fb6932ba9a2b |
| parent 218 | 87fd3589b65a |
| child 256 | f4b443fcddc7 |
| permissions | -rw-r--r-- |
| 21 | 1 |
# -*- coding: utf-8 -*- |
2 |
''' |
|
3 |
Created on Jan 28, 2013 |
|
4 |
||
5 |
@author: ymh |
|
6 |
''' |
|
7 |
||
8 |
from django.db import models |
|
9 |
from django.contrib.auth.models import User |
|
| 159 | 10 |
from django.contrib.contenttypes.models import ContentType |
11 |
from django.contrib.contenttypes import generic |
|
| 218 | 12 |
from egonomy.utils.queries import cache_generics |
| 21 | 13 |
|
14 |
class ImageMetadata(models.Model): |
|
15 |
||
16 |
id = models.CharField(null=False, blank=False, max_length=15, primary_key=True) |
|
17 |
date_inserted = models.DateTimeField(null=False, blank=False, auto_now_add=True) |
|
18 |
date_modified = models.DateTimeField(null=False, blank=False, auto_now=True) |
|
19 |
||
20 |
cliche = models.CharField(null=False, blank=False, max_length=15) |
|
21 |
inventaire = models.TextField(null=True, blank=True) |
|
22 |
titre = models.TextField(null=True, blank=True) |
|
23 |
description = models.TextField(null=True, blank=True) |
|
24 |
date = models.IntegerField(null=True, blank=True) |
|
25 |
longueur = models.DecimalField(null=True, blank=True, max_digits=20, decimal_places=15) |
|
26 |
hauteur = models.DecimalField(null=True, blank=True, max_digits=20, decimal_places=15) |
|
27 |
profondeur = models.DecimalField(null=True, blank=True, max_digits=20, decimal_places=15) |
|
28 |
diametre = models.DecimalField(null=True, blank=True, max_digits=20, decimal_places=15) |
|
29 |
photographe = models.TextField(null=True, blank=True) |
|
30 |
auteur = models.TextField(null=True, blank=True) |
|
31 |
droits = models.TextField(null=True, blank=True) |
|
32 |
mentions = models.TextField(null=True, blank=True) |
|
33 |
periode = models.TextField(null=True, blank=True) |
|
34 |
technique = models.TextField(null=True, blank=True) |
|
35 |
site = models.TextField(null=True, blank=True) |
|
36 |
lieu = models.TextField(null=True, blank=True) |
|
37 |
localisation = models.TextField(null=True, blank=True) |
|
38 |
mots_cles = models.TextField(null=True, blank=True) |
|
39 |
||
40 |
titre_pertimm = models.TextField(null=True, blank=True) |
|
41 |
description_pertimm = models.TextField(null=True, blank=True) |
|
42 |
thesaurus_pertimm = models.TextField(null=True, blank=True) |
|
| 67 | 43 |
|
44 |
@property |
|
|
69
412ab5e76c65
Clickable tags to easily add tags from rmn and pertimm.
cavaliet
parents:
67
diff
changeset
|
45 |
def mots_cles_list(self): |
|
412ab5e76c65
Clickable tags to easily add tags from rmn and pertimm.
cavaliet
parents:
67
diff
changeset
|
46 |
return self.mots_cles.split(",") |
|
412ab5e76c65
Clickable tags to easily add tags from rmn and pertimm.
cavaliet
parents:
67
diff
changeset
|
47 |
|
|
412ab5e76c65
Clickable tags to easily add tags from rmn and pertimm.
cavaliet
parents:
67
diff
changeset
|
48 |
@property |
|
412ab5e76c65
Clickable tags to easily add tags from rmn and pertimm.
cavaliet
parents:
67
diff
changeset
|
49 |
def titre_pertimm_list(self): |
|
412ab5e76c65
Clickable tags to easily add tags from rmn and pertimm.
cavaliet
parents:
67
diff
changeset
|
50 |
return self.titre_pertimm.split(",") |
|
412ab5e76c65
Clickable tags to easily add tags from rmn and pertimm.
cavaliet
parents:
67
diff
changeset
|
51 |
|
|
412ab5e76c65
Clickable tags to easily add tags from rmn and pertimm.
cavaliet
parents:
67
diff
changeset
|
52 |
@property |
|
412ab5e76c65
Clickable tags to easily add tags from rmn and pertimm.
cavaliet
parents:
67
diff
changeset
|
53 |
def description_pertimm_list(self): |
|
412ab5e76c65
Clickable tags to easily add tags from rmn and pertimm.
cavaliet
parents:
67
diff
changeset
|
54 |
return self.description_pertimm.split(",") |
|
412ab5e76c65
Clickable tags to easily add tags from rmn and pertimm.
cavaliet
parents:
67
diff
changeset
|
55 |
|
|
412ab5e76c65
Clickable tags to easily add tags from rmn and pertimm.
cavaliet
parents:
67
diff
changeset
|
56 |
@property |
|
412ab5e76c65
Clickable tags to easily add tags from rmn and pertimm.
cavaliet
parents:
67
diff
changeset
|
57 |
def thesaurus_pertimm_list(self): |
|
412ab5e76c65
Clickable tags to easily add tags from rmn and pertimm.
cavaliet
parents:
67
diff
changeset
|
58 |
return self.thesaurus_pertimm.replace("|", ",").split(",") |
| 140 | 59 |
|
60 |
@property |
|
| 175 | 61 |
def tag_list(self): |
| 140 | 62 |
# all keywords mots_cles + titre_pertimm+ description_pertimm + thesaurus_pertimmreturn |
63 |
# merged into one sorted list |
|
64 |
moc = self.mots_cles.split(",") |
|
65 |
tip = self.titre_pertimm.split(",") |
|
66 |
dep = self.description_pertimm.split(",") |
|
67 |
thp = self.thesaurus_pertimm.replace("|", ",").split(",") |
|
68 |
# sort by alphabetical order (sorted) and remove duplicates (set) |
|
69 |
l = sorted(list(set(moc + tip + dep + thp)), key=unicode.lower) |
|
70 |
return l |
|
| 21 | 71 |
|
72 |
||
73 |
class ImageInfo(models.Model): |
|
74 |
||
75 |
id = models.CharField(null=False, blank=False, max_length=15, primary_key=True) |
|
76 |
image_file = models.ImageField(width_field = "width", height_field= "height", upload_to="images/", max_length=2048) |
|
77 |
width = models.IntegerField(null=False, blank=False) |
|
78 |
height = models.IntegerField(null=False, blank=False) |
|
79 |
mimetype = models.CharField(null=True, blank=True, max_length=1024) |
|
80 |
exif = models.TextField(null=True, blank=True) #json value for exif data if available |
|
81 |
||
82 |
||
83 |
class Image(models.Model): |
|
84 |
||
85 |
id = models.CharField(null=False, blank=False, max_length=15, primary_key=True) |
|
86 |
metadata = models.ForeignKey(ImageMetadata) |
|
87 |
info = models.ForeignKey(ImageInfo, null=True, blank=True) |
|
| 175 | 88 |
|
89 |
@property |
|
90 |
def tag_list(self): |
|
91 |
return self.metadata.tag_list |
|
| 21 | 92 |
|
93 |
||
94 |
class Fragment(models.Model): |
|
95 |
||
96 |
image = models.ForeignKey(Image, blank=False, null=False) |
|
97 |
date_created = models.DateTimeField(blank=False, null=False, auto_now_add=True) |
|
98 |
date_saved = models.DateTimeField(blank=False, null=False, auto_now=True) |
|
99 |
coordinates = models.TextField(blank=False, null=False) |
|
100 |
author = models.ForeignKey(User, blank=False, null=False) |
|
101 |
title = models.CharField(max_length=2048, blank=True, null=True) |
|
102 |
description = models.TextField(blank=True, null=True) |
|
103 |
tags = models.TextField(blank=True, null=True) |
|
| 74 | 104 |
|
| 149 | 105 |
@property |
106 |
def tag_list(self): |
|
107 |
# tags in list |
|
108 |
return self.tags.split(",") |
|
109 |
||
| 74 | 110 |
|
111 |
def get_viewbox_info(self): |
|
| 89 | 112 |
if not self.coordinates or self.coordinates=="MZ" or self.coordinates=="": |
| 74 | 113 |
return None,None,None,None |
114 |
# Now we split the coordinates to get the path points's max and min x and y |
|
115 |
# A typical path is M0.1995 0.1574L0.3718 0.0131L0.7731 0.0597L0.5126 0.2915Z |
|
116 |
points_str = self.coordinates.strip("M").strip("Z").split("L") |
|
117 |
points_x = [] |
|
118 |
points_y = [] |
|
119 |
for p in points_str: |
|
120 |
xy = p.split(" ") |
|
121 |
points_x.append(float(xy[0])) |
|
122 |
points_y.append(float(xy[1])) |
|
123 |
# At this point, values are floats like 19.95, 15.74... |
|
124 |
min_x = min(points_x) |
|
125 |
max_x = max(points_x) |
|
126 |
min_y = min(points_y) |
|
127 |
max_y = max(points_y) |
|
128 |
# At this point, values are floats like 19, 15... |
|
129 |
# Now we build the viewbox, which is min_x min_y (max_x-min_x) (max_y-min_y) with number like 0.19 0.15... |
|
130 |
# We use floor and +2 for the viewbox to be a bit larger than the strict fragment |
|
131 |
vb_x = min_x |
|
132 |
vb_y = min_y |
|
133 |
vb_w = max_x - min_x |
|
134 |
vb_h = max_y - min_y |
|
135 |
return vb_x, vb_y, vb_w, vb_h |
|
136 |
||
137 |
# This property returns a ratio between width and height |
|
138 |
@property |
|
139 |
def ratio(self): |
|
| 89 | 140 |
if not self.coordinates or self.coordinates=="MZ" or self.coordinates=="": |
|
93
0a75599363e9
Senseetive api : generate fragment with good ratio and not forced square.
cavaliet
parents:
89
diff
changeset
|
141 |
return 1 |
| 74 | 142 |
_, _, vb_w, vb_h = self.get_viewbox_info() |
143 |
return vb_w/vb_h |
|
144 |
||
145 |
# This property returns a viewbox used in the swg xml and enbling to see the fragment only |
|
146 |
@property |
|
147 |
def viewbox(self): |
|
| 89 | 148 |
if not self.coordinates or self.coordinates=="MZ" or self.coordinates=="": |
| 74 | 149 |
return "0 0 1 1" |
150 |
vb_x, vb_y, vb_w, vb_h = self.get_viewbox_info() |
|
151 |
vb = str(vb_x) + " " + str(vb_y) + " " + str(vb_w) + " " + str(vb_h) |
|
152 |
return vb |
|
153 |
||
154 |
# This property returns a square viewbox used in the swg xml and enbling to see the fragment only |
|
155 |
@property |
|
156 |
def viewbox_square(self): |
|
| 89 | 157 |
if not self.coordinates or self.coordinates=="MZ" or self.coordinates=="": |
| 74 | 158 |
return "0 0 1 1" |
159 |
vb_x, vb_y, vb_w, vb_h = self.get_viewbox_info() |
|
160 |
img_info = self.image.info |
|
161 |
img_ratio = float(img_info.width) / float(img_info.height) |
|
162 |
if vb_w > vb_h: |
|
163 |
# If fragment w > h, we center the fragment on y ... |
|
164 |
vb_y = max(0, vb_y - (((vb_w * img_ratio) - vb_h) / 2)) |
|
165 |
# ... and resize the viewbox's h with image's ratio |
|
166 |
vb_h = vb_w * img_ratio |
|
167 |
else: |
|
| 140 | 168 |
# If fragment w <= h, we center the fragment on x ... |
| 74 | 169 |
vb_x = max(0, vb_x - (((vb_h / img_ratio) - vb_w) / 2)) |
170 |
# ... and we resize the viewbox's w with image's ratio |
|
171 |
vb_w = vb_h / img_ratio |
|
172 |
vb = str(vb_x) + " " + str(vb_y) + " " + str(vb_w) + " " + str(vb_h) |
|
173 |
||
174 |
return vb |
|
| 140 | 175 |
|
| 159 | 176 |
|
177 |
||
| 140 | 178 |
class Collection(models.Model): |
179 |
||
|
191
d7b30914607d
enhance collection and add slideshow with images and fragments.
cavaliet
parents:
175
diff
changeset
|
180 |
LIST = 1 |
| 140 | 181 |
MOSAIC = 2 |
|
191
d7b30914607d
enhance collection and add slideshow with images and fragments.
cavaliet
parents:
175
diff
changeset
|
182 |
SLIDESHOW = 3 |
|
d7b30914607d
enhance collection and add slideshow with images and fragments.
cavaliet
parents:
175
diff
changeset
|
183 |
GEOGRAPHICAL = 4 |
| 140 | 184 |
|
| 159 | 185 |
PUBLICATION_CHOICES = ( |
|
191
d7b30914607d
enhance collection and add slideshow with images and fragments.
cavaliet
parents:
175
diff
changeset
|
186 |
(LIST, 'list'), |
|
d7b30914607d
enhance collection and add slideshow with images and fragments.
cavaliet
parents:
175
diff
changeset
|
187 |
(MOSAIC, 'mosaic'), |
| 140 | 188 |
(SLIDESHOW, 'slideshow'), |
189 |
(GEOGRAPHICAL, 'geographical') |
|
190 |
) |
|
191 |
||
192 |
||
193 |
title = models.CharField(max_length=2048, blank=True, null=True) |
|
194 |
description = models.TextField(blank=True, null=True) |
|
195 |
author = models.ForeignKey(User, blank=False, null=False) |
|
196 |
creation = models.DateTimeField(auto_now_add=True) |
|
197 |
modification = models.DateTimeField(auto_now=True) |
|
| 159 | 198 |
public = models.BooleanField(null=False, default=True) # Collection is published or not, always published by default |
|
191
d7b30914607d
enhance collection and add slideshow with images and fragments.
cavaliet
parents:
175
diff
changeset
|
199 |
publication_type = models.IntegerField(choices=PUBLICATION_CHOICES, default=1) # list, mosaic, slideshow or geographical |
| 218 | 200 |
|
201 |
@property |
|
202 |
def first_four_items(self): |
|
203 |
items = CollectionItem.objects.filter(collection=self).select_related('author', 'content_type', 'object_id', 'content_object').order_by("order")[:4] |
|
204 |
cache_generics(items) |
|
205 |
return items |
|
| 159 | 206 |
|
207 |
||
208 |
||
209 |
class CollectionItem(models.Model): |
|
210 |
||
211 |
content_type = models.ForeignKey(ContentType) # can be image ou fragment |
|
| 168 | 212 |
object_id = models.CharField(null=False, blank=False, max_length=15) # has to be char because of image id |
| 159 | 213 |
content_object = generic.GenericForeignKey('content_type', 'object_id') |
214 |
description = models.TextField(blank=True, null=True) |
|
215 |
order = models.IntegerField() |
|
216 |
# An item belongs to only one collection. Collection will have "items" related name. |
|
217 |
collection = models.ForeignKey(Collection, related_name='items') |
|
| 140 | 218 |
|
219 |
||
220 |
||
| 21 | 221 |