src/egonomy/models.py
author cavaliet
Wed, 10 Jul 2013 15:31:38 +0200
changeset 230 fb6932ba9a2b
parent 218 87fd3589b65a
child 256 f4b443fcddc7
permissions -rw-r--r--
update registration and password management, and version number to 0.6.10

# -*- coding: utf-8 -*-
'''
Created on Jan 28, 2013

@author: ymh
'''

from django.db import models
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from egonomy.utils.queries import cache_generics

class ImageMetadata(models.Model):
    
    id = models.CharField(null=False, blank=False, max_length=15, primary_key=True)
    date_inserted = models.DateTimeField(null=False, blank=False, auto_now_add=True)
    date_modified = models.DateTimeField(null=False, blank=False, auto_now=True)
    
    cliche = models.CharField(null=False, blank=False, max_length=15)
    inventaire = models.TextField(null=True, blank=True)
    titre = models.TextField(null=True, blank=True)
    description = models.TextField(null=True, blank=True)
    date = models.IntegerField(null=True, blank=True)
    longueur = models.DecimalField(null=True, blank=True, max_digits=20, decimal_places=15)
    hauteur = models.DecimalField(null=True, blank=True, max_digits=20, decimal_places=15)
    profondeur = models.DecimalField(null=True, blank=True, max_digits=20, decimal_places=15)
    diametre = models.DecimalField(null=True, blank=True, max_digits=20, decimal_places=15)
    photographe = models.TextField(null=True, blank=True)
    auteur = models.TextField(null=True, blank=True)
    droits = models.TextField(null=True, blank=True)
    mentions = models.TextField(null=True, blank=True)
    periode = models.TextField(null=True, blank=True)
    technique = models.TextField(null=True, blank=True)
    site = models.TextField(null=True, blank=True)
    lieu = models.TextField(null=True, blank=True)
    localisation = models.TextField(null=True, blank=True)
    mots_cles = models.TextField(null=True, blank=True)
    
    titre_pertimm = models.TextField(null=True, blank=True)
    description_pertimm = models.TextField(null=True, blank=True)
    thesaurus_pertimm = models.TextField(null=True, blank=True)
    
    @property
    def mots_cles_list(self):
        return self.mots_cles.split(",")
    
    @property
    def titre_pertimm_list(self):
        return self.titre_pertimm.split(",")
    
    @property
    def description_pertimm_list(self):
        return self.description_pertimm.split(",")
    
    @property
    def thesaurus_pertimm_list(self):
        return self.thesaurus_pertimm.replace("|", ",").split(",")
    
    @property
    def tag_list(self):
        # all keywords mots_cles + titre_pertimm+ description_pertimm + thesaurus_pertimmreturn
        # merged into one sorted list
        moc = self.mots_cles.split(",")
        tip = self.titre_pertimm.split(",")
        dep = self.description_pertimm.split(",")
        thp = self.thesaurus_pertimm.replace("|", ",").split(",")
        # sort by alphabetical order (sorted) and remove duplicates (set)
        l = sorted(list(set(moc + tip + dep + thp)), key=unicode.lower)
        return l


class ImageInfo(models.Model):
    
    id = models.CharField(null=False, blank=False, max_length=15, primary_key=True)
    image_file = models.ImageField(width_field = "width", height_field= "height", upload_to="images/", max_length=2048)
    width = models.IntegerField(null=False, blank=False)
    height = models.IntegerField(null=False, blank=False)
    mimetype = models.CharField(null=True, blank=True, max_length=1024)
    exif = models.TextField(null=True, blank=True) #json value for exif data if available

    
class Image(models.Model):
    
    id = models.CharField(null=False, blank=False, max_length=15, primary_key=True)
    metadata = models.ForeignKey(ImageMetadata)
    info = models.ForeignKey(ImageInfo, null=True, blank=True)
    
    @property
    def tag_list(self):
        return self.metadata.tag_list

    
class Fragment(models.Model):
    
    image = models.ForeignKey(Image, blank=False, null=False)
    date_created = models.DateTimeField(blank=False, null=False, auto_now_add=True)
    date_saved = models.DateTimeField(blank=False, null=False, auto_now=True)
    coordinates = models.TextField(blank=False, null=False)
    author = models.ForeignKey(User, blank=False, null=False)
    title = models.CharField(max_length=2048, blank=True, null=True)
    description = models.TextField(blank=True, null=True)
    tags = models.TextField(blank=True, null=True)
    
    @property
    def tag_list(self):
        # tags in list
        return self.tags.split(",")
    
    
    def get_viewbox_info(self):
        if not self.coordinates or self.coordinates=="MZ" or self.coordinates=="":
            return None,None,None,None
        # Now we split the coordinates to get the path points's max and min x and y
        # A typical path is M0.1995 0.1574L0.3718 0.0131L0.7731 0.0597L0.5126 0.2915Z
        points_str = self.coordinates.strip("M").strip("Z").split("L")
        points_x = []
        points_y = []
        for p in points_str:
            xy = p.split(" ")
            points_x.append(float(xy[0]))
            points_y.append(float(xy[1]))
        # At this point, values are floats like 19.95, 15.74...
        min_x = min(points_x)
        max_x = max(points_x)
        min_y = min(points_y)
        max_y = max(points_y)
        # At this point, values are floats like 19, 15...
        # Now we build the viewbox, which is min_x min_y (max_x-min_x) (max_y-min_y) with number like 0.19 0.15...
        # We use floor and +2 for the viewbox to be a bit larger than the strict fragment
        vb_x = min_x
        vb_y = min_y
        vb_w = max_x - min_x
        vb_h = max_y - min_y
        return vb_x, vb_y, vb_w, vb_h
    
    # This property returns a ratio between width and height
    @property
    def ratio(self):
        if not self.coordinates or self.coordinates=="MZ" or self.coordinates=="":
            return 1
        _, _, vb_w, vb_h = self.get_viewbox_info()
        return vb_w/vb_h
    
    # This property returns a viewbox used in the swg xml and enbling to see the fragment only
    @property
    def viewbox(self):
        if not self.coordinates or self.coordinates=="MZ" or self.coordinates=="":
            return "0 0 1 1"
        vb_x, vb_y, vb_w, vb_h = self.get_viewbox_info()
        vb = str(vb_x) + " " + str(vb_y) + " " + str(vb_w) + " " + str(vb_h)
        return vb
    
    # This property returns a square viewbox used in the swg xml and enbling to see the fragment only
    @property
    def viewbox_square(self):
        if not self.coordinates or self.coordinates=="MZ" or self.coordinates=="":
            return "0 0 1 1"
        vb_x, vb_y, vb_w, vb_h = self.get_viewbox_info()
        img_info = self.image.info
        img_ratio = float(img_info.width) / float(img_info.height)
        if vb_w > vb_h:
            # If fragment w > h, we center the fragment on y ...
            vb_y = max(0, vb_y - (((vb_w * img_ratio) - vb_h) / 2))
            # ... and resize the viewbox's h with image's ratio
            vb_h = vb_w * img_ratio
        else:
            # If fragment w <= h, we center the fragment on x ...
            vb_x = max(0, vb_x - (((vb_h / img_ratio) - vb_w) / 2))
            # ... and we resize the viewbox's w with image's ratio
            vb_w = vb_h / img_ratio
        vb = str(vb_x) + " " + str(vb_y) + " " + str(vb_w) + " " + str(vb_h)
        
        return vb



class Collection(models.Model):
    
    LIST = 1
    MOSAIC = 2
    SLIDESHOW = 3
    GEOGRAPHICAL = 4
      
    PUBLICATION_CHOICES = (
    (LIST, 'list'),
    (MOSAIC, 'mosaic'),
    (SLIDESHOW, 'slideshow'),
    (GEOGRAPHICAL, 'geographical')
    )
    
    
    title = models.CharField(max_length=2048, blank=True, null=True)
    description = models.TextField(blank=True, null=True)
    author = models.ForeignKey(User, blank=False, null=False)
    creation = models.DateTimeField(auto_now_add=True)
    modification = models.DateTimeField(auto_now=True)
    public = models.BooleanField(null=False, default=True) # Collection is published or not, always published by default
    publication_type = models.IntegerField(choices=PUBLICATION_CHOICES, default=1) # list, mosaic, slideshow or geographical
    
    @property
    def first_four_items(self):
        items = CollectionItem.objects.filter(collection=self).select_related('author', 'content_type', 'object_id', 'content_object').order_by("order")[:4]
        cache_generics(items)
        return items



class CollectionItem(models.Model):
    
    content_type = models.ForeignKey(ContentType) # can be image ou fragment
    object_id = models.CharField(null=False, blank=False, max_length=15) # has to be char because of image id
    content_object = generic.GenericForeignKey('content_type', 'object_id')
    description = models.TextField(blank=True, null=True)
    order = models.IntegerField()
    # An item belongs to only one collection. Collection will have "items" related name.
    collection = models.ForeignKey(Collection, related_name='items')