1 from django.db import models
2 import catalogue.models
3 from django.db.models import permalink
4 from sorl.thumbnail import ImageField
5 from django.conf import settings
6 from django.core.files.storage import FileSystemStorage
7 from django.utils.datastructures import SortedDict
8 from django.template.loader import render_to_string
9 from django.core.cache import cache
10 from catalogue.utils import split_tags
11 from django.utils.safestring import mark_safe
12 from librarian import dcparser
13 from slughifi import slughifi
15 from django.utils.translation import ugettext_lazy as _
16 from newtagging import managers
20 picture_storage = FileSystemStorage(location=path.join(settings.MEDIA_ROOT, 'pictures'), base_url=settings.MEDIA_URL + "pictures/")
23 class Picture(models.Model):
28 title = models.CharField(_('title'), max_length=120)
29 slug = models.SlugField(_('slug'), max_length=120, db_index=True, unique=True)
30 sort_key = models.CharField(_('sort key'), max_length=120, db_index=True, editable=False)
31 created_at = models.DateTimeField(_('creation date'), auto_now_add=True, db_index=True)
32 changed_at = models.DateTimeField(_('creation date'), auto_now=True, db_index=True)
33 xml_file = models.FileField('xml_file', upload_to="xml", storage=picture_storage)
34 image_file = ImageField(_('image_file'), upload_to="images", storage=picture_storage)
35 objects = models.Manager()
36 tagged = managers.ModelTaggedItemManager(catalogue.models.Tag)
37 tags = managers.TagDescriptor(catalogue.models.Tag)
39 class AlreadyExists(Exception):
43 ordering = ('sort_key',)
45 verbose_name = _('picture')
46 verbose_name_plural = _('pictures')
48 URLID_RE = r'[a-z0-9-]+'
49 FILEID_RE = r'[a-z0-9-]+'
51 def save(self, force_insert=False, force_update=False, reset_short_html=True, **kwargs):
52 from sortify import sortify
54 self.sort_key = sortify(self.title)
56 ret = super(Picture, self).save(force_insert, force_update)
59 self.reset_short_html()
63 def __unicode__(self):
67 def get_absolute_url(self):
68 return ('picture.views.picture_detail', [self.urlid()])
74 def from_xml_file(cls, xml_file, image_file=None, overwrite=False):
76 Import xml and it's accompanying image file.
77 If image file is missing, it will be fetched by librarian.picture.ImageStore
78 which looks for an image file in the same directory the xml is, with extension matching
81 from sortify import sortify
82 from django.core.files import File
83 from librarian.picture import WLPicture
84 close_xml_file = False
85 close_image_file = False
86 # class SimpleImageStore(object):
87 # def path(self_, slug, mime_type):
88 # """Returns the image file. Ignores slug ad mime_type."""
91 if image_file is not None and not isinstance(image_file, File):
92 image_file = File(open(image_file))
93 close_image_file = True
95 if not isinstance(xml_file, File):
96 xml_file = File(open(xml_file))
100 # use librarian to parse meta-data
101 picture_xml = WLPicture.from_file(xml_file)
102 # image_store=SimpleImageStore
104 picture, created = Picture.objects.get_or_create(slug=picture_xml.slug)
105 if not created and not overwrite:
106 raise Picture.AlreadyExists('Picture %s already exists' % picture_xml.slug)
108 picture.title = picture_xml.picture_info.title
111 for part in picture_xml.partiter():
112 for motif in part['themes']:
113 tag, created = catalogue.models.Tag.objects.get_or_create(slug=slughifi(motif), category='theme')
116 tag.sort_key = sortify(tag.name)
120 picture.tags = catalogue.models.Tag.tags_from_info(picture_xml.picture_info) + \
123 if image_file is not None:
126 img = picture_xml.image_file()
128 # FIXME: hardcoded extension
129 picture.image_file.save(path.basename(picture_xml.image_path), File(img))
131 picture.xml_file.save("%s.xml" % picture.slug, File(xml_file))
141 def picture_list(cls, filter=None):
142 """Generates a hierarchical listing of all pictures
143 Pictures are optionally filtered with a test function.
146 pics = cls.objects.all().order_by('sort_key')\
147 .only('title', 'slug', 'image_file')
150 pics = pics.filter(filter).distinct()
152 pics_by_author = SortedDict()
154 for tag in catalogue.models.Tag.objects.filter(category='author'):
155 pics_by_author[tag] = []
158 authors = list(pic.tags.filter(category='author'))
160 for author in authors:
161 pics_by_author[author].append(pic)
165 return pics_by_author, orphans
169 if not hasattr(self, '_info'):
170 info = dcparser.parse(self.xml_file.path, picture.PictureInfo)
174 def reset_short_html(self):
178 cache_key = "Picture.short_html/%d" % (self.id)
179 cache.delete(cache_key)
181 def short_html(self):
183 cache_key = "Picture.short_html/%d" % (self.id)
184 short_html = cache.get(cache_key)
188 if short_html is not None:
189 return mark_safe(short_html)
191 tags = self.tags.filter(category__in=('author', 'kind', 'epoch'))
192 tags = split_tags(tags)
194 short_html = unicode(render_to_string('picture/picture_short.html',
195 {'picture': self, 'tags': tags}))
198 cache.set(cache_key, short_html, catalogue.models.CACHE_FOREVER)
199 return mark_safe(short_html)