# -'- Encoding: utf-8 -*- import os from django.conf import settings from django.core.urlresolvers import reverse from django.db import models from django.db.models import Q from django.template.defaultfilters import slugify from django.utils.timezone import now from django.utils.translation import ugettext as _ from ckeditor.fields import RichTextField from easy_thumbnails.fields import ThumbnailerImageField from utils import COUNTRIES, OverwriteStorage def get_upload_path(instance, filename): """ Generates the desired file path and filename for an uploaded Image. With this function Django can save the uploaded images to subfolders that also have a meaning for humans. @param instance: an Django Object for which the Image has been uploaded. @type instance: a instace of an models.Model sub-class. @param filename: The filename of the uploaded image. @type filename: String """ filename, extension = os.path.splitext(filename.lower()) if isinstance(instance, Event): return "events/{date:%Y-%m-%d}/{name}{ext}".format( date=instance.start, name=slugify(instance.name), ext=extension ) elif isinstance(instance, Location): return "events/locations/{name}{ext}".format( name=slugify(instance.name), ext=extension ) elif isinstance(instance, Photo): return "events/{date:%Y-%m-%d}/{name}{ext}".format( date=instance.event.start, name=filename, ext=extension ) class EventManager(models.Manager): def get_queryset(self): return super(EventManager, self).get_queryset().select_related('location') def current_event(self): try: current = self.filter(start__lte=now()) current = current.filter(end__gte=now()) return current.order_by('start', 'end')[0] except IndexError: return None def next_event(self): try: return self.filter(start__gt=now()).order_by('start', 'end')[0] except IndexError: return None def archive(self): return self.filter(start__lt=now()) def latest_events(self, num=3): return self.filter(start__lt=now()).order_by('-start', '-end')[:num] def upcoming(self, limit=None): result = self.filter(start__gt=now()).order_by('start', 'end') if limit: return result[0:limit] else: return result class Event(models.Model): name = models.CharField(_('Name'), max_length=255) description = RichTextField(_("Description"), blank=True) location = models.ForeignKey('Location') start = models.DateTimeField(_('Start')) end = models.DateTimeField(_('End'), blank=True, null=True) url = models.URLField(_('Homepage'), blank=True) image = ThumbnailerImageField( _("Image"), upload_to=get_upload_path, storage=OverwriteStorage(), blank=True, null=True ) mahjong_tournament = models.BooleanField( _('Mahjong Tournament'), default=False, help_text=_(u'This event is a tournament, different rules apply for \ the kyu ranking.') ) mahjong_season = models.PositiveSmallIntegerField( _('Mahjong Season'), blank=True, null=True ) photo_count = models.PositiveIntegerField(default=0, editable=False) event_series = models.ForeignKey('Event', blank=True, null=True, on_delete=models.SET_NULL, editable=True, verbose_name=_('Event Series'), help_text=_(u'Wenn dieser Event zu einer Veranstaltungsreihe gehört \ werden Ort, Beschreibung, Bild und Homepage von dem hier angegebenen \ Event übernommen.') ) objects = EventManager() class Meta(object): verbose_name = _('Event') verbose_name_plural = _('Events') ordering = ('start', 'end',) def __unicode__(self): try: return "%(name)s (%(date)s)" % {'name': self.name, 'date': self.start.date()} except: return "New Event Model" def get_absolute_url(self): kwargs = { 'pk': self.id, 'year': self.start.strftime('%Y'), 'month': self.start.strftime('%m') } return reverse('event-detail', kwargs=kwargs) def get_eventseries_form_url(self): kwargs = { 'pk': self.id, 'year': self.start.strftime('%Y'), 'month': self.start.strftime('%m') } return reverse('eventseries-form', kwargs=kwargs) def get_edit_url(self): kwargs = { 'pk': self.id, 'year': self.start.strftime('%Y'), 'month': self.start.strftime('%m') } return reverse('event-form', kwargs=kwargs) def get_image(self): if self.image: return self.image elif self.photo_count: return self.photo_set.all().order_by('?')[0].image elif self.location.image: return self.location.image else: return None def save(self, **kwargs): # Fülle fehlende Felder mit den Angaben der Hauptveranstaltung aus. if self.event_series: master_event = self.event_series self.name = self.name or master_event.name self.description = self.description or master_event.description self.location = master_event.location self.url = master_event.url self.image = self.image or master_event.image self.photo_count = self.photo_set.count() super(Event, self).save(**kwargs) # Update the Hanchans if necesery: for hanchan in self.hanchan_set.all(): hanchan.save() class Location(models.Model): name = models.CharField(_("Name"), max_length=200) description = RichTextField(_("Description"), blank=True) image = ThumbnailerImageField( _("Image"), upload_to=get_upload_path, storage=OverwriteStorage(), blank=True, null=True ) url = models.URLField(_('Homepage'), blank=True) postal_code = models.CharField(_('Postal Code'), max_length=6) street_address = models.CharField(_('Street Address'), max_length=127) locality = models.CharField(_('Locality'), max_length=127) country = models.CharField(_('Country'), max_length=2, choices=COUNTRIES) class Meta(object): verbose_name = _('Venue') verbose_name_plural = _('Venues') def __unicode__(self): return self.name @property def address(self): address = (self.street_address, self.locality, self.country,) return ','.join(address) class PhotoManager(models.Manager): def get_random(self, startpage=True): if startpage: queryset = self.filter(on_startpage=True) else: queryset = self.all().order_by('?')[0] try: return queryset.order_by('?')[0] except IndexError: return Photo() class Photo(models.Model): name = models.CharField(_("Name"), max_length=100, blank=True) image = ThumbnailerImageField(_("Image"), upload_to=get_upload_path, storage=OverwriteStorage()) event = models.ForeignKey('events.Event') description = models.TextField( _("Description"), max_length=300, blank=True ) photographer = models.ForeignKey(settings.AUTH_USER_MODEL) on_startpage = models.BooleanField( _("Startpage"), default=False, db_index=True, help_text=_('Display this Photo on the Startpage Teaser') ) created_date = models.DateTimeField(_("Published on")) views = models.PositiveIntegerField( _("Number of views"), editable=False, default=0 ) objects = PhotoManager() metadata = None orientation = 1 class Meta: get_latest_by = "created_date" ordering = ["created_date"] db_table = 'events_photo' verbose_name = _('Event Image') verbose_name_plural = _('Event Images') def __unicode__(self): return os.path.basename(self.image.name) def rotate(self, rotate): # TODO: Eine vernüftigte Methode ohne viele Abhängigkeiten finden um # die Bilder bei Bedarf zu drehen. if rotate == 'clockwise': pass elif rotate == 'counter-clockwise': pass self.save() def save(self, **kwargs): super(Photo, self).save(**kwargs) self.event.save() def get_absolute_url(self): return reverse( 'event-photo', kwargs={'event': self.event.id, 'pk': self.id} ) @property def next_photo(self): queryset = Photo.objects.filter(created_date__gt=self.created_date) queryset = queryset.order_by('created_date') try: if self.event.event_series: return queryset.filter( Q(event=self.event) | Q(event=self.event.event_series) | Q(event__event_series=self.event.event_series) )[0] else: return queryset.filter( Q(event=self.event) | Q(event__event_series=self.event) )[0] except IndexError: return None return self.get_next_by_created_date(event=self.event) @property def previous_photo(self): queryset = Photo.objects.filter(created_date__lt=self.created_date) queryset = queryset.order_by('-created_date') try: if self.event.event_series: return queryset.filter( Q(event=self.event) | Q(event=self.event.event_series) | Q(event__event_series=self.event.event_series) )[0] else: return queryset.filter( Q(event=self.event) | Q(event__event_series=self.event) )[0] except IndexError: return None return self.get_previous_by_created_date(event=self.event)