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.contrib.auth.models import User
6 from django.core.exceptions import ValidationError
7 from django.db import models
8 from django.db.models import permalink
9 from django.utils.translation import ugettext, ugettext_lazy as _
10 from newtagging.models import TagBase
13 # Those are hard-coded here so that makemessages sees them.
15 ('author', _('author')),
16 ('epoch', _('epoch')),
18 ('genre', _('genre')),
19 ('theme', _('theme')),
26 """A tag attachable to books and fragments (and possibly anything).
28 Used to represent searchable metadata (authors, epochs, genres, kinds),
29 fragment themes (motifs) and some book hierarchy related kludges."""
30 name = models.CharField(_('name'), max_length=50, db_index=True)
31 slug = models.SlugField(_('slug'), max_length=120, db_index=True)
32 sort_key = models.CharField(_('sort key'), max_length=120, db_index=True)
33 category = models.CharField(_('category'), max_length=50, blank=False, null=False,
34 db_index=True, choices=TAG_CATEGORIES)
35 description = models.TextField(_('description'), blank=True)
37 user = models.ForeignKey(User, blank=True, null=True)
38 book_count = models.IntegerField(_('book count'), blank=True, null=True)
39 gazeta_link = models.CharField(blank=True, max_length=240)
40 wiki_link = models.CharField(blank=True, max_length=240)
42 created_at = models.DateTimeField(_('creation date'), auto_now_add=True, db_index=True)
43 changed_at = models.DateTimeField(_('creation date'), auto_now=True, db_index=True)
45 class UrlDeprecationWarning(DeprecationWarning):
56 categories_dict = dict((item[::-1] for item in categories_rev.iteritems()))
59 ordering = ('sort_key',)
60 verbose_name = _('tag')
61 verbose_name_plural = _('tags')
62 unique_together = (("slug", "category"),)
63 app_label = 'catalogue'
65 def __unicode__(self):
69 return "Tag(slug=%r)" % self.slug
72 def get_absolute_url(self):
73 return ('catalogue.views.tagged_object_list', [self.url_chunk])
76 if self.category == 'book' and (self.gazeta_link or self.wiki_link):
77 raise ValidationError(ugettext(
78 u"Book tags can't have attached links. Set them directly on the book instead of it's tag."))
82 def create_url(cls, category, slug):
83 return ('catalogue.views.tagged_object_list', [
84 '/'.join((cls.categories_dict[category], slug))
87 def has_description(self):
88 return len(self.description) > 0
89 has_description.short_description = _('description')
90 has_description.boolean = True
93 """Returns global book count for book tags, fragment count for themes."""
94 from catalogue.models import Book, Fragment
96 if self.category == 'book':
98 objects = Book.objects.none()
99 elif self.category == 'theme':
100 objects = Fragment.tagged.with_all((self,))
102 objects = Book.tagged.with_all((self,)).order_by()
103 if self.category != 'set':
104 # eliminate descendants
105 l_tags = Tag.objects.filter(slug__in=[book.book_tag_slug() for book in objects.iterator()])
106 descendants_keys = [book.pk for book in Book.tagged.with_any(l_tags).iterator()]
108 objects = objects.exclude(pk__in=descendants_keys)
109 return objects.count()
112 def get_tag_list(tags):
113 if isinstance(tags, basestring):
118 tags_splitted = tags.split('/')
119 for name in tags_splitted:
121 real_tags.append(Tag.objects.get(slug=name, category=category))
123 elif name in Tag.categories_rev:
124 category = Tag.categories_rev[name]
127 real_tags.append(Tag.objects.exclude(category='book').get(slug=name))
129 except Tag.MultipleObjectsReturned, e:
130 ambiguous_slugs.append(name)
133 # something strange left off
134 raise Tag.DoesNotExist()
136 # some tags should be qualified
137 e = Tag.MultipleObjectsReturned()
139 e.ambiguous_slugs = ambiguous_slugs
142 e = Tag.UrlDeprecationWarning()
147 return TagBase.get_tag_list(tags)
151 return '/'.join((Tag.categories_dict[self.category], self.slug))
154 def tags_from_info(info):
155 from fnpdjango.utils.text.slughifi import slughifi
156 from sortify import sortify
158 categories = (('kinds', 'kind'), ('genres', 'genre'), ('authors', 'author'), ('epochs', 'epoch'))
159 for field_name, category in categories:
161 tag_names = getattr(info, field_name)
164 tag_names = [getattr(info, category)]
166 # For instance, Pictures do not have 'genre' field.
168 for tag_name in tag_names:
169 tag_sort_key = tag_name
170 if category == 'author':
171 tag_sort_key = tag_name.last_name
172 tag_name = tag_name.readable()
173 tag, created = Tag.objects.get_or_create(slug=slughifi(tag_name), category=category)
176 tag.sort_key = sortify(tag_sort_key.lower())
178 meta_tags.append(tag)