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, ImageStore
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=ImageStore(picture_storage.path('images')))
103 # image_store=SimpleImageStore
105 picture, created = Picture.objects.get_or_create(slug=picture_xml.slug)
106 if not created and not overwrite:
107 raise Picture.AlreadyExists('Picture %s already exists' % picture_xml.slug)
109 picture.title = picture_xml.picture_info.title
112 for part in picture_xml.partiter():
113 for motif in part['themes']:
114 tag, created = catalogue.models.Tag.objects.get_or_create(slug=slughifi(motif), category='theme')
117 tag.sort_key = sortify(tag.name)
121 picture.tags = catalogue.models.Tag.tags_from_info(picture_xml.picture_info) + \
124 if image_file is not None:
127 img = picture_xml.image_file()
129 # FIXME: hardcoded extension
130 picture.image_file.save(path.basename(picture_xml.image_path), File(img))
132 picture.xml_file.save("%s.xml" % picture.slug, File(xml_file))
142 def picture_list(cls, filter=None):
143 """Generates a hierarchical listing of all pictures
144 Pictures are optionally filtered with a test function.
147 pics = cls.objects.all().order_by('sort_key')\
148 .only('title', 'slug', 'image_file')
151 pics = pics.filter(filter).distinct()
153 pics_by_author = SortedDict()
155 for tag in catalogue.models.Tag.objects.filter(category='author'):
156 pics_by_author[tag] = []
159 authors = list(pic.tags.filter(category='author'))
161 for author in authors:
162 pics_by_author[author].append(pic)
166 return pics_by_author, orphans
170 if not hasattr(self, '_info'):
171 info = dcparser.parse(self.xml_file.path, picture.PictureInfo)
175 def reset_short_html(self):
179 cache_key = "Picture.short_html/%d" % (self.id)
180 cache.delete(cache_key)
182 def short_html(self):
184 cache_key = "Picture.short_html/%d" % (self.id)
185 short_html = cache.get(cache_key)
189 if short_html is not None:
190 return mark_safe(short_html)
192 tags = self.tags.filter(category__in=('author', 'kind', 'epoch'))
193 tags = split_tags(tags)
195 short_html = unicode(render_to_string('picture/picture_short.html',
196 {'picture': self, 'tags': tags}))
199 cache.set(cache_key, short_html, catalogue.models.CACHE_FOREVER)
200 return mark_safe(short_html)