1 # -*- coding: utf-8 -*-
2 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
3 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
5 from django.conf import settings
6 from django.contrib.auth.models import User
7 from django.core.exceptions import ValidationError
8 from django.db import models
9 from django.db.models import permalink
10 from django.utils.translation import ugettext, ugettext_lazy as _
11 from newtagging.models import TagBase
14 # Those are hard-coded here so that makemessages sees them.
16 ('author', _('author')),
17 ('epoch', _('epoch')),
19 ('genre', _('genre')),
20 ('theme', _('theme')),
27 """A tag attachable to books and fragments (and possibly anything).
29 Used to represent searchable metadata (authors, epochs, genres, kinds),
30 fragment themes (motifs) and some book hierarchy related kludges."""
31 name = models.CharField(_('name'), max_length=50, db_index=True)
32 slug = models.SlugField(_('slug'), max_length=120, db_index=True)
33 sort_key = models.CharField(_('sort key'), max_length=120, db_index=True)
34 category = models.CharField(_('category'), max_length=50, blank=False, null=False,
35 db_index=True, choices=TAG_CATEGORIES)
36 description = models.TextField(_('description'), blank=True)
38 user = models.ForeignKey(User, blank=True, null=True)
39 book_count = models.IntegerField(_('book count'), blank=True, null=True)
40 gazeta_link = models.CharField(blank=True, max_length=240)
41 wiki_link = models.CharField(blank=True, max_length=240)
43 created_at = models.DateTimeField(_('creation date'), auto_now_add=True, db_index=True)
44 changed_at = models.DateTimeField(_('creation date'), auto_now=True, db_index=True)
46 class UrlDeprecationWarning(DeprecationWarning):
57 categories_dict = dict((item[::-1] for item in categories_rev.iteritems()))
60 ordering = ('sort_key',)
61 verbose_name = _('tag')
62 verbose_name_plural = _('tags')
63 unique_together = (("slug", "category"),)
64 app_label = 'catalogue'
66 def __unicode__(self):
70 return "Tag(slug=%r)" % self.slug
73 def get_absolute_url(self):
74 return ('catalogue.views.tagged_object_list', [self.url_chunk])
77 if self.category == 'book' and (self.gazeta_link or self.wiki_link):
78 raise ValidationError(ugettext(
79 u"Book tags can't have attached links. Set them directly on the book instead of it's tag."))
83 def create_url(cls, category, slug):
84 return ('catalogue.views.tagged_object_list', [
85 '/'.join((cls.categories_dict[category], slug))
88 def has_description(self):
89 return len(self.description) > 0
90 has_description.short_description = _('description')
91 has_description.boolean = True
94 """Returns global book count for book tags, fragment count for themes."""
95 from catalogue.models import Book, Fragment
97 if self.category == 'book':
99 objects = Book.objects.none()
100 elif self.category == 'theme':
101 objects = Fragment.tagged.with_all((self,))
103 objects = Book.tagged.with_all((self,)).order_by()
104 if self.category != 'set':
105 # eliminate descendants
106 l_tags = Tag.objects.filter(slug__in=[book.book_tag_slug() for book in objects.iterator()])
107 descendants_keys = [book.pk for book in Book.tagged.with_any(l_tags).iterator()]
109 objects = objects.exclude(pk__in=descendants_keys)
110 return objects.count()
113 def get_tag_list(tags):
114 if isinstance(tags, basestring):
119 tags_splitted = tags.split('/')
120 for name in tags_splitted:
122 real_tags.append(Tag.objects.get(slug=name, category=category))
124 elif name in Tag.categories_rev:
125 category = Tag.categories_rev[name]
128 real_tags.append(Tag.objects.exclude(category='book').get(slug=name))
130 except Tag.MultipleObjectsReturned, e:
131 ambiguous_slugs.append(name)
134 # something strange left off
135 raise Tag.DoesNotExist()
137 # some tags should be qualified
138 e = Tag.MultipleObjectsReturned()
140 e.ambiguous_slugs = ambiguous_slugs
143 e = Tag.UrlDeprecationWarning()
148 return TagBase.get_tag_list(tags)
152 return '/'.join((Tag.categories_dict[self.category], self.slug))
155 def tags_from_info(info):
156 from fnpdjango.utils.text.slughifi import slughifi
157 from sortify import sortify
159 categories = (('kinds', 'kind'), ('genres', 'genre'), ('authors', 'author'), ('epochs', 'epoch'))
160 for field_name, category in categories:
162 tag_names = getattr(info, field_name)
165 tag_names = [getattr(info, category)]
167 # For instance, Pictures do not have 'genre' field.
169 for tag_name in tag_names:
170 lang = getattr(tag_name, 'lang', settings.LANGUAGE_CODE)
171 tag_sort_key = tag_name
172 if category == 'author':
173 tag_sort_key = tag_name.last_name
174 tag_name = tag_name.readable()
175 if lang == settings.LANGUAGE_CODE:
176 # Allow creating new tag, if it's in default language.
177 tag, created = Tag.objects.get_or_create(slug=slughifi(tag_name), category=category)
180 setattr(tag, "name_%s" % lang, tag_name)
181 tag.sort_key = sortify(tag_sort_key.lower())
183 meta_tags.append(tag)
185 # Ignore unknown tags in non-default languages.
187 tag = Tag.objects.get(category=category, **{"name_%s" % lang: tag_name})
188 except Tag.DoesNotExist:
191 meta_tags.append(tag)