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 get_cache
10 from catalogue.utils import split_tags
11 from django.utils.safestring import mark_safe
12 from fnpdjango.utils.text.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 def save(self, force_insert=False, force_update=False, reset_short_html=True, **kwargs):
48 from sortify import sortify
50 self.sort_key = sortify(self.title)
52 ret = super(Picture, self).save(force_insert, force_update)
55 self.reset_short_html()
59 def __unicode__(self):
63 def get_absolute_url(self):
64 return ('picture.views.picture_detail', [self.slug])
67 def from_xml_file(cls, xml_file, image_file=None, overwrite=False):
69 Import xml and it's accompanying image file.
70 If image file is missing, it will be fetched by librarian.picture.ImageStore
71 which looks for an image file in the same directory the xml is, with extension matching
74 from sortify import sortify
75 from django.core.files import File
76 from librarian.picture import WLPicture, ImageStore
77 close_xml_file = False
78 close_image_file = False
79 # class SimpleImageStore(object):
80 # def path(self_, slug, mime_type):
81 # """Returns the image file. Ignores slug ad mime_type."""
84 if image_file is not None and not isinstance(image_file, File):
85 image_file = File(open(image_file))
86 close_image_file = True
88 if not isinstance(xml_file, File):
89 xml_file = File(open(xml_file))
93 # use librarian to parse meta-data
94 picture_xml = WLPicture.from_file(xml_file,
95 image_store=ImageStore(picture_storage.path('images')))
96 # image_store=SimpleImageStore
98 picture, created = Picture.objects.get_or_create(slug=picture_xml.slug)
99 if not created and not overwrite:
100 raise Picture.AlreadyExists('Picture %s already exists' % picture_xml.slug)
102 picture.title = picture_xml.picture_info.title
105 for part in picture_xml.partiter():
106 for motif in part['themes']:
107 tag, created = catalogue.models.Tag.objects.get_or_create(slug=slughifi(motif), category='theme')
110 tag.sort_key = sortify(tag.name)
114 picture.tags = catalogue.models.Tag.tags_from_info(picture_xml.picture_info) + \
117 if image_file is not None:
120 img = picture_xml.image_file()
122 # FIXME: hardcoded extension
123 picture.image_file.save(path.basename(picture_xml.image_path), File(img))
125 picture.xml_file.save("%s.xml" % picture.slug, File(xml_file))
135 def picture_list(cls, filter=None):
136 """Generates a hierarchical listing of all pictures
137 Pictures are optionally filtered with a test function.
140 pics = cls.objects.all().order_by('sort_key')\
141 .only('title', 'slug', 'image_file')
144 pics = pics.filter(filter).distinct()
146 pics_by_author = SortedDict()
148 for tag in catalogue.models.Tag.objects.filter(category='author'):
149 pics_by_author[tag] = []
151 for pic in pics.iterator():
152 authors = list(pic.tags.filter(category='author'))
154 for author in authors:
155 pics_by_author[author].append(pic)
159 return pics_by_author, orphans
163 if not hasattr(self, '_info'):
164 from librarian import dcparser
165 from librarian import picture
166 info = dcparser.parse(self.xml_file.path, picture.PictureInfo)
170 def reset_short_html(self):
174 cache_key = "Picture.short_html/%d" % (self.id)
175 get_cache('permanent').delete(cache_key)
177 def short_html(self):
179 cache_key = "Picture.short_html/%d" % (self.id)
180 short_html = get_cache('permanent').get(cache_key)
184 if short_html is not None:
185 return mark_safe(short_html)
187 tags = self.tags.filter(category__in=('author', 'kind', 'epoch', 'genre'))
188 tags = split_tags(tags)
190 short_html = unicode(render_to_string('picture/picture_short.html',
191 {'picture': self, 'tags': tags}))
194 get_cache('permanent').set(cache_key, short_html)
195 return mark_safe(short_html)