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 slughifi import slughifi
14 from django.utils.translation import ugettext_lazy as _
15 from newtagging import managers
19 picture_storage = FileSystemStorage(location=path.join(settings.MEDIA_ROOT, 'pictures'), base_url=settings.MEDIA_URL + "pictures/")
22 class Picture(models.Model):
27 title = models.CharField(_('title'), max_length=120)
28 slug = models.SlugField(_('slug'), max_length=120, db_index=True, unique=True)
29 sort_key = models.CharField(_('sort key'), max_length=120, db_index=True, editable=False)
30 created_at = models.DateTimeField(_('creation date'), auto_now_add=True, db_index=True)
31 changed_at = models.DateTimeField(_('creation date'), auto_now=True, db_index=True)
32 xml_file = models.FileField('xml_file', upload_to="xml", storage=picture_storage)
33 image_file = ImageField(_('image_file'), upload_to="images", storage=picture_storage)
34 objects = models.Manager()
35 tagged = managers.ModelTaggedItemManager(catalogue.models.Tag)
36 tags = managers.TagDescriptor(catalogue.models.Tag)
38 class AlreadyExists(Exception):
42 ordering = ('sort_key',)
44 verbose_name = _('picture')
45 verbose_name_plural = _('pictures')
47 URLID_RE = r'[a-z0-9-]+'
48 FILEID_RE = r'[a-z0-9-]+'
50 def save(self, force_insert=False, force_update=False, reset_short_html=True, **kwargs):
51 from sortify import sortify
53 self.sort_key = sortify(self.title)
55 ret = super(Picture, self).save(force_insert, force_update)
58 self.reset_short_html()
62 def __unicode__(self):
66 def get_absolute_url(self):
67 return ('picture.views.picture_detail', [self.urlid()])
73 def from_xml_file(cls, xml_file, image_file=None, overwrite=False):
75 Import xml and it's accompanying image file.
76 If image file is missing, it will be fetched by librarian.picture.ImageStore
77 which looks for an image file in the same directory the xml is, with extension matching
80 from sortify import sortify
81 from django.core.files import File
82 from librarian.picture import WLPicture, ImageStore
83 close_xml_file = False
84 close_image_file = False
85 # class SimpleImageStore(object):
86 # def path(self_, slug, mime_type):
87 # """Returns the image file. Ignores slug ad mime_type."""
90 if image_file is not None and not isinstance(image_file, File):
91 image_file = File(open(image_file))
92 close_image_file = True
94 if not isinstance(xml_file, File):
95 xml_file = File(open(xml_file))
99 # use librarian to parse meta-data
100 picture_xml = WLPicture.from_file(xml_file,
101 image_store=ImageStore(picture_storage.path('images')))
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 from librarian import dcparser
171 from librarian import picture
172 info = dcparser.parse(self.xml_file.path, picture.PictureInfo)
176 def reset_short_html(self):
180 cache_key = "Picture.short_html/%d" % (self.id)
181 cache.delete(cache_key)
183 def short_html(self):
185 cache_key = "Picture.short_html/%d" % (self.id)
186 short_html = cache.get(cache_key)
190 if short_html is not None:
191 return mark_safe(short_html)
193 tags = self.tags.filter(category__in=('author', 'kind', 'epoch'))
194 tags = split_tags(tags)
196 short_html = unicode(render_to_string('picture/picture_short.html',
197 {'picture': self, 'tags': tags}))
200 cache.set(cache_key, short_html, catalogue.models.CACHE_FOREVER)
201 return mark_safe(short_html)