summaryrefslogtreecommitdiff
path: root/chimere/models.py
diff options
context:
space:
mode:
Diffstat (limited to 'chimere/models.py')
-rw-r--r--chimere/models.py791
1 files changed, 451 insertions, 340 deletions
diff --git a/chimere/models.py b/chimere/models.py
index 122d61f..f605e08 100644
--- a/chimere/models.py
+++ b/chimere/models.py
@@ -20,7 +20,11 @@
"""
Models description
"""
-import os, datetime, pyexiv2, re, string, copy
+import os
+import datetime
+import pyexiv2
+import re
+import copy
import simplejson as json
from lxml import etree
from PIL import Image
@@ -29,12 +33,10 @@ from BeautifulSoup import BeautifulSoup
from django import forms
from django.conf import settings
-from django.contrib import admin
from django.contrib.auth.models import User, Permission, ContentType, Group
from django.contrib.gis.db import models
-from django.contrib.gis.gdal import SpatialReference
from django.core.files import File
-from django.core.exceptions import ValidationError, ObjectDoesNotExist
+from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import reverse
from django.db.models import Q
from django.db.models.signals import post_save, pre_save, m2m_changed
@@ -42,9 +44,7 @@ from django.template import defaultfilters
from django.utils.translation import ugettext_lazy as _
from chimere.widgets import HiddenPointChooserWidget, PointField, RouteField, \
- SelectMultipleField, TextareaWidget, \
- DatePickerWidget
-from chimere.managers import BaseGeoManager
+ SelectMultipleField, TextareaWidget, DatePickerWidget, PolygonField
from chimere.utils import KMLManager, OSMManager, ShapefileManager, \
GeoRSSManager, CSVManager, HtmlXsltManager, XMLXsltManager, JsonManager, \
IcalManager
@@ -61,13 +61,16 @@ class Page(models.Model):
template_path = models.CharField(_(u"Template path"), max_length=150,
blank=True, null=True)
content = models.TextField(blank=True, null=True)
- def __unicode__(self):
- ordering = ["order"]
- return self.title
+
class Meta:
+ ordering = ["order"]
verbose_name = _(u"Page")
verbose_name_plural = _(u"Page")
+ def __unicode__(self):
+ return self.title
+
+
def page_post_save(sender, **kwargs):
if not kwargs['instance']:
return
@@ -77,6 +80,7 @@ def page_post_save(sender, **kwargs):
page.save()
post_save.connect(page_post_save, sender=Page)
+
def shortify(text):
if not text:
return ''
@@ -89,15 +93,16 @@ def shortify(text):
if c == '>':
break
if c == '<':
- short_desc = desc[:-(idx+1)]
+ short_desc = desc[:-(idx + 1)]
break
if not short_desc:
for idx, c in enumerate(reversed(desc)):
if c == ' ' or c == '\n':
- short_desc = desc[:-(idx+1)]
+ short_desc = desc[:-(idx + 1)]
break
return BeautifulSoup(short_desc).prettify()
+
class News(models.Model):
"""News of the site
"""
@@ -110,33 +115,39 @@ class News(models.Model):
url = models.URLField(_(u"Url"), max_length=200, blank=True, null=True)
areas = SelectMultipleField('Area', verbose_name=_(u"Associated areas"),
blank=True, null=True)
- def __unicode__(self):
- ordering = ["-date"]
- return self.title
+
class Meta:
+ ordering = ["-date"]
verbose_name = _(u"News")
verbose_name_plural = _(u"News")
+ def __unicode__(self):
+ return self.title
+
@property
def short_desc(self):
return shortify(self.content)
+
class TinyUrl(models.Model):
"""Tinyfied version of permalink parameters
"""
- parameters = models.CharField(_(u"Parameters"), max_length=500, unique=True)
- def __unicode__(self):
- return self.parameters
- class Meta:
- verbose_name = _(u"TinyUrl")
+ parameters = models.CharField(_(u"Parameters"), max_length=500,
+ unique=True)
digits = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
base = len(digits)
+ class Meta:
+ verbose_name = _(u"TinyUrl")
+
+ def __unicode__(self):
+ return self.parameters
+
@classmethod
def getParametersByUrn(cls, urn):
c_id = 0
for idx, char in enumerate(reversed(urn)):
- c_id += cls.digits.index(char)*pow(cls.base, idx)
+ c_id += cls.digits.index(char) * pow(cls.base, idx)
try:
params = cls.objects.get(id=c_id).parameters
except cls.DoesNotExist:
@@ -160,27 +171,34 @@ class TinyUrl(models.Model):
break
return urn
+
class ColorTheme(models.Model):
"""Color theme
"""
name = models.CharField(_(u"Name"), max_length=150)
- def __unicode__(self):
- return self.name
+
class Meta:
verbose_name = _(u"Color theme")
+ def __unicode__(self):
+ return self.name
+
+
class Color(models.Model):
"""Color
"""
code = models.CharField(_(u"Code"), max_length=6)
order = models.IntegerField(_(u"Order"))
color_theme = models.ForeignKey(ColorTheme, verbose_name=_(u"Color theme"))
- def __unicode__(self):
- return self.code
+
class Meta:
ordering = ["order"]
verbose_name = _(u"Color")
+ def __unicode__(self):
+ return self.code
+
+
class Category(models.Model):
"""Category of Point Of Interest (POI)
"""
@@ -188,12 +206,15 @@ class Category(models.Model):
available = models.BooleanField(_(u"Available"))
order = models.IntegerField(_(u"Order"))
description = models.TextField(blank=True, null=True)
- def __unicode__(self):
- return self.name
+
class Meta:
ordering = ["order"]
verbose_name = _(u"Category")
+ def __unicode__(self):
+ return self.name
+
+
class Icon(models.Model):
'''Icon
'''
@@ -202,11 +223,18 @@ class Icon(models.Model):
height_field='height', width_field='width')
height = models.IntegerField(_(u"Height"))
width = models.IntegerField(_(u"Width"))
+ offset_x = models.IntegerField(_(u"Offset x"), default=10)
+ offset_y = models.IntegerField(_(u"Offset y"), default=20)
+ popup_offset_x = models.IntegerField(_(u"Popup offset x"), default=5)
+ popup_offset_y = models.IntegerField(_(u"Popup offset y"), default=20)
+
def __unicode__(self):
return self.name
+
class Meta:
verbose_name = _(u"Icon")
+
class SubCategory(models.Model):
'''Sub-category
'''
@@ -218,13 +246,15 @@ class SubCategory(models.Model):
default=True)
TYPE = (('M', _(u'Marker')),
('R', _(u'Route')),
+ ('P', _(u'Polygon')),
('B', _(u'Both')),)
item_type = models.CharField(_(u"Item type"), max_length=1, choices=TYPE)
dated = models.BooleanField(_(u"Is dated"), default=False)
description = models.TextField(blank=True, null=True)
icon = models.ForeignKey(Icon, verbose_name=_(u"Icon"))
- hover_icon = models.ForeignKey(Icon, verbose_name=_(u"Hover icon"),
- blank=True, null=True, related_name='subcat_hovered')
+ hover_icon = models.ForeignKey(
+ Icon, verbose_name=_(u"Hover icon"), blank=True, null=True,
+ related_name='subcat_hovered')
color_theme = models.ForeignKey(ColorTheme, verbose_name=_(u"Color theme"),
blank=True, null=True)
as_layer = models.BooleanField(_(u"Displayed in the layer menu"),
@@ -232,14 +262,16 @@ class SubCategory(models.Model):
routing_warn = models.BooleanField(_(u"Routing warn"), default=False)
order = models.IntegerField(_(u"Order"), default=1000)
keywords = models.TextField(_(u"Keywords"), max_length=200,
- blank=True, null=True)
- def __unicode__(self):
- return u"%s / %s" % (self.category.name, self.name)
+ blank=True, null=True)
+
class Meta:
ordering = ["category", "order"]
verbose_name = _(u"Sub-category")
verbose_name_plural = _(u"Sub-categories")
+ def __unicode__(self):
+ return u"%s / %s" % (self.category.name, self.name)
+
@classmethod
def getAvailable(cls, item_types=None, area_name=None, public=False):
'''Get list of tuples with first the category and second the associated
@@ -270,8 +302,8 @@ class SubCategory(models.Model):
sub_category.category.selected = True
sub_categories[sub_category.category].append(sub_category)
- subcategories = [(cat, subcats) \
- for cat, subcats in sub_categories.items()]
+ subcategories = [(cat, subcats)
+ for cat, subcats in sub_categories.items()]
get_cat_order = lambda cat_tuple: cat_tuple[0].order
subcategories = sorted(subcategories, key=get_cat_order)
return subcategories
@@ -286,15 +318,20 @@ class SubCategory(models.Model):
return cats
def getJSONDict(self):
- items = {'id':self.pk, 'name':self.name,
- 'description':self.description if self.description\
- else '',
- 'icon':{'url':self.icon.image.url,
- 'width':self.icon.image.width,
- 'height':self.icon.image.height}
- }
+ items = {'id': self.pk, 'name': self.name,
+ 'description': self.description if self.description
+ else '',
+ 'icon': {'url': self.icon.image.url,
+ 'width': self.icon.image.width,
+ 'height': self.icon.image.height,
+ 'offset_x': self.icon.offset_x,
+ 'offset_y': self.icon.offset_y,
+ 'popup_offset_x': self.icon.popup_offset_x,
+ 'popup_offset_y': self.icon.popup_offset_y}
+ }
+
if self.hover_icon:
- items['icon_hover'] = {'url':self.hover_icon.image.url}
+ items['icon_hover'] = {'url': self.hover_icon.image.url}
return items
def getJSON(self, categories_id=[]):
@@ -370,10 +407,10 @@ class Importer(models.Model):
source = models.CharField(_(u"Web address"), max_length=200,
blank=True, null=True,
help_text=_(u"Don't forget the trailing slash"))
- source_file = models.FileField(_(u"Source file"),
- upload_to='import_files', blank=True, null=True)
- source_file_alt = models.FileField(_(u"Alt source file"),
- upload_to='import_files', blank=True, null=True)
+ source_file = models.FileField(
+ _(u"Source file"), upload_to='import_files', blank=True, null=True)
+ source_file_alt = models.FileField(
+ _(u"Alt source file"), upload_to='import_files', blank=True, null=True)
default_name = models.CharField(_(u"Name by default"), max_length=200,
blank=True, null=True)
srid = models.IntegerField(_(u"SRID"), blank=True, null=True)
@@ -388,19 +425,20 @@ class Importer(models.Model):
blank=True, null=True)
license = models.CharField(_(u"License"), max_length=1000,
blank=True, null=True)
- categories = SelectMultipleField(SubCategory, blank=True, null=True,
- verbose_name=_(u"Associated subcategories"))
+ categories = SelectMultipleField(
+ SubCategory, blank=True, null=True,
+ verbose_name=_(u"Associated subcategories"))
state = models.TextField(_(u"State"), blank=True, null=True)
- associate_marker_to_way = models.BooleanField(_(u"Automatically associate "\
- u"a marker to a way"), default=False)
+ associate_marker_to_way = models.BooleanField(
+ _(u"Automatically associate a marker to a way"), default=False)
automatic_update = models.BooleanField(_(u"Automatically updated"),
default=False)
default_status = models.CharField(_(u"Default status"), max_length=1,
choices=STATUS, default='I')
- default_localisation = PointField(_(u"Default localisation"),
- srid=settings.CHIMERE_EPSG_DISPLAY_PROJECTION,
- blank=True, null=True,
- widget=HiddenPointChooserWidget)
+ default_localisation = PointField(
+ _(u"Default localisation"),
+ srid=settings.CHIMERE_EPSG_DISPLAY_PROJECTION, blank=True, null=True,
+ widget=HiddenPointChooserWidget)
class Meta:
verbose_name = _(u"Importer")
@@ -446,47 +484,139 @@ class ImporterKeyCategories(models.Model):
class Meta:
verbose_name = _(u"Importer - Key categories")
+
class GeographicItem(models.Model):
name = models.TextField(_(u"Name"))
categories = SelectMultipleField(SubCategory)
- submiter_session_key = models.CharField(_(u"Submitter session key"),
- blank=True, null=True, max_length=40)
+ submiter_session_key = models.CharField(
+ _(u"Submitter session key"), blank=True, null=True, max_length=40)
submiter_name = models.CharField(_(u"Submitter name or nickname"),
blank=True, null=True, max_length=40)
submiter_email = models.EmailField(_(u"Submitter email"), blank=True,
null=True)
- submiter_comment = models.TextField(_(u"Submitter comment"), max_length=200,
- blank=True, null=True)
+ submiter_comment = models.TextField(_(u"Submitter comment"),
+ max_length=200, blank=True, null=True)
status = models.CharField(_(u"Status"), max_length=1, choices=STATUS)
- keywords = models.TextField(_(u"Keywords"), max_length=200,
- blank=True, null=True)
+ keywords = models.TextField(_(u"Keywords"), max_length=200, blank=True,
+ null=True)
import_key = models.CharField(_(u"Import key"), max_length=200,
blank=True, null=True)
import_version = models.IntegerField(_(u"Import version"),
blank=True, null=True)
import_source = models.CharField(_(u"Source"), max_length=200,
blank=True, null=True)
- modified_since_import = models.BooleanField(_(u"Modified since last import"),
- default=True)
+ modified_since_import = models.BooleanField(
+ _(u"Modified since last import"), default=True)
not_for_osm = models.BooleanField(_(u"Not to be exported to OSM"),
default=False)
origin = models.CharField(_(u"Origin"), max_length=1000,
blank=True, null=True)
license = models.CharField(_(u"License"), max_length=1000,
blank=True, null=True)
- start_date = models.DateField(_(u"Start date"), blank=True, null=True,
- help_text=_(u"Not mandatory. Set it for dated item such as event. "\
+ start_date = models.DateField(
+ _(u"Start date"), blank=True, null=True,
+ help_text=_(u"Not mandatory. Set it for dated item such as event. "
u"Format YYYY-MM-DD"))
- end_date = models.DateField(_(u"End date"), blank=True, null=True,
- help_text=_(u"Not mandatory. Set it only if you have a multi-day "\
+ end_date = models.DateField(
+ _(u"End date"), blank=True, null=True,
+ help_text=_(u"Not mandatory. Set it only if you have a multi-day "
u"event. Format YYYY-MM-DD"))
+
class Meta:
abstract = True
+ def __unicode__(self):
+ return self.name
+
+ def __init__(self, *args, **kwargs):
+ super(GeographicItem, self).__init__(*args, **kwargs)
+ # add read attributes for properties
+ for pm in self.all_properties():
+ attr_name = pm.getAttrName()
+ if not hasattr(self, attr_name):
+ val = ''
+ property = self.getProperty(pm)
+ if property:
+ val = property.python_value
+ setattr(self, attr_name, val)
+ if not hasattr(self, attr_name + '_set'):
+ setattr(self, attr_name + '_set',
+ property_setter(self.__class__, pm))
+
+ @property
+ def geometry(self):
+ return getattr(self, self.geom_attr).wkt
+
+ def getProperty(self, propertymodel, safe=None):
+ """Get the property of an associated property model.
+ If safe set to True, verify if the property is available
+ """
+ if safe and not propertymodel.available:
+ return
+ try:
+ property = Property.objects.get(propertymodel=propertymodel,
+ marker=self)
+ except Property.DoesNotExist:
+ return
+ return property
+
+ def getProperties(self):
+ """Get all the property availables
+ """
+ properties = []
+ for pm in PropertyModel.objects.filter(available=True):
+ property = self.getProperty(pm)
+ if property:
+ properties.append(property)
+ return properties
+
+ def setProperty(self, pm, value):
+ u"""
+ Set a property
+ """
+ properties = Property.objects.filter(marker=self,
+ propertymodel=pm).all()
+ # in case of multiple edition as the same time delete arbitrary
+ # the others
+ if len(properties) > 1:
+ for property in properties[1:]:
+ property.delete()
+ if pm.type == 'C' and value:
+ try:
+ value = str(int(value))
+ except ValueError:
+ choice = PropertyModelChoice.objects.filter(propertymodel=pm,
+ value=value)
+ if choice.count():
+ value = choice.all()[0].pk
+ else:
+ choice = PropertyModelChoice.objects.create(
+ value=value, propertymodel=pm)
+ value = choice.pk
+ # new property
+ if not properties:
+ new_property = Property.objects.create(
+ marker=self, propertymodel=pm, value=value)
+ new_property.save()
+ else:
+ property = properties[0]
+ property.value = value
+ property.save()
+
+ def saveProperties(self, values):
+ """
+ Save properties
+ """
+ for propertymodel in PropertyModel.objects.filter(available=True):
+ val = u""
+ if unicode(propertymodel.id) in values:
+ val = values[unicode(propertymodel.id)]
+ self.setProperty(propertymodel, val)
+
def get_key(self, key):
key_vals = self.import_key.split(';')
for k_v in key_vals:
- if k_v.startswith(key+':'):
+ if k_v.startswith(key + ':'):
return k_v.split(':')[1]
def set_key(self, key, value):
@@ -513,8 +643,8 @@ class GeographicItem(models.Model):
def has_modified(self):
if (self.ref_item and self.ref_item != self) \
- or self.__class__.objects.filter(ref_item=self
- ).exclude(pk=self.pk).count():
+ or self.__class__.objects.filter(
+ ref_item=self).exclude(pk=self.pk).count():
return True
return False
@@ -526,6 +656,7 @@ class GeographicItem(models.Model):
def all_properties(cls):
return [pm for pm in PropertyModel.objects.all()]
+
def property_setter(cls, propertymodel):
def setter(self, value):
marker = self
@@ -536,15 +667,17 @@ def property_setter(cls, propertymodel):
marker.setProperty(propertymodel, value)
return setter
+
class Marker(GeographicItem):
'''Marker for a POI
'''
- ref_item = models.ForeignKey("Marker", blank=True, null=True,
- verbose_name=_(u"Reference marker"), related_name='submited_marker')
+ ref_item = models.ForeignKey(
+ "Marker", blank=True, null=True, verbose_name=_(u"Reference marker"),
+ related_name='submited_marker')
point = PointField(_(u"Localisation"),
srid=settings.CHIMERE_EPSG_DISPLAY_PROJECTION)
available_date = models.DateTimeField(_(u"Available Date"), blank=True,
- null=True) # used by feeds
+ null=True) # used by feeds
route = models.ForeignKey(u"Route", blank=True, null=True,
related_name='associated_marker')
description = models.TextField(_(u"Description"), blank=True, null=True)
@@ -552,23 +685,9 @@ class Marker(GeographicItem):
null=True)
objects = models.GeoManager()
- def __unicode__(self):
- return self.name
-
- def __init__(self, *args, **kwargs):
- super(Marker, self).__init__(*args, **kwargs)
- # add read attributes for properties
- for pm in self.all_properties():
- attr_name = pm.getAttrName()
- if not hasattr(self, attr_name):
- val = ''
- property = self.getProperty(pm)
- if property:
- val = property.python_value
- setattr(self, attr_name, val)
- if not hasattr(self, attr_name + '_set'):
- setattr(self, attr_name + '_set',
- property_setter(self.__class__, pm))
+ class Meta:
+ ordering = ('status', 'name')
+ verbose_name = _(u"Point of interest")
def get_init_multi(self):
multis = [forms.model_to_dict(multi)
@@ -609,17 +728,9 @@ class Marker(GeographicItem):
return shortify(self.description)
@property
- def geometry(self):
- return self.point.wkt
-
- @property
def geom_attr(self):
return 'point'
- class Meta:
- ordering = ('status', 'name')
- verbose_name = _(u"Point of interest")
-
def getLatitude(self):
'''Return the latitude
'''
@@ -630,93 +741,32 @@ class Marker(GeographicItem):
'''
return self.point.x
- def getProperty(self, propertymodel, safe=None):
- """Get the property of an associated property model.
- If safe set to True, verify if the property is available
- """
- if safe and not propertymodel.available:
- return
- try:
- property = Property.objects.get(propertymodel=propertymodel,
- marker=self)
- except Property.DoesNotExist:
- return
- return property
-
- def getProperties(self):
- """Get all the property availables
- """
- properties = []
- for pm in PropertyModel.objects.filter(available=True):
- property = self.getProperty(pm)
- if property:
- properties.append(property)
- return properties
-
- def setProperty(self, pm, value):
- u"""
- Set a property
- """
- properties = Property.objects.filter(marker=self,
- propertymodel=pm).all()
- # in case of multiple edition as the same time delete arbitrary
- # the others
- if len(properties) > 1:
- for property in properties[1:]:
- property.delete()
- if pm.type == 'C' and value:
- try:
- value = str(int(value))
- except ValueError:
- choice = PropertyModelChoice.objects.filter(propertymodel=pm,
- value=value)
- if choice.count():
- value = choice.all()[0].pk
- else:
- choice = PropertyModelChoice.objects.create(value=value,
- propertymodel=pm)
- value = choice.pk
- # new property
- if not properties:
- new_property = Property.objects.create(marker=self,
- propertymodel=pm,
- value=value)
- new_property.save()
- else:
- property = properties[0]
- property.value = value
- property.save()
-
- def saveProperties(self, values):
- """
- Save properties
- """
- for propertymodel in PropertyModel.objects.filter(available=True):
- val = u""
- if unicode(propertymodel.id) in values:
- val = values[unicode(propertymodel.id)]
- self.setProperty(propertymodel, val)
-
def getGeoJSON(self, categories_id=[]):
'''Return a GeoJSON string
'''
jsons = []
- json_tpl = {"type":"Feature", "properties":{}}
+ json_tpl = {"type": "Feature", "properties": {}}
for cat in self.categories.all():
if categories_id and cat.id not in categories_id:
continue
items = copy.deepcopy(json_tpl)
items['geometry'] = json.loads(self.point.geojson)
items['properties'].update({
- 'pk':self.id,
- 'name':self.name,
- 'icon_path':unicode(cat.icon.image),
- 'icon_hover_path':unicode(cat.hover_icon.image) \
- if cat.hover_icon else '',
- 'category_name':cat.name})
+ 'pk': self.id,
+ 'name': self.name,
+ 'icon_path': unicode(cat.icon.image),
+ 'icon_hover_path': unicode(cat.hover_icon.image)
+ if cat.hover_icon else '',
+ 'icon_offset_x': cat.icon.offset_x,
+ 'icon_offset_y': cat.icon.offset_y,
+ 'icon_popup_offset_x': cat.icon.popup_offset_x,
+ 'icon_popup_offset_y': cat.icon.popup_offset_y,
+ 'category_name': cat.name})
try:
- items['properties'].update({'icon_width':cat.icon.image.width,
- 'icon_height':cat.icon.image.height,})
+ items['properties'].update(
+ {'icon_width': cat.icon.image.width,
+ 'icon_height': cat.icon.image.height,
+ })
except IOError:
pass
@@ -742,11 +792,13 @@ class Marker(GeographicItem):
return url
PRE_ATTRS = {
- 'Marker':('name', 'description', 'start_date', 'geometry', 'import_version',
- 'modified_since_import'),
- 'Route':('name', 'geometry', 'import_version', 'modified_since_import'),
- 'Area':('urn', 'name'),
- }
+ 'Marker': ('name', 'description', 'start_date', 'geometry',
+ 'import_version', 'modified_since_import'),
+ 'Route': ('name', 'geometry', 'import_version', 'modified_since_import'),
+ 'Area': ('urn', 'name'),
+}
+
+
def geometry_pre_save(cls, pre_save_geom_values):
def geom_pre_save(sender, **kwargs):
if not kwargs['instance'] or not kwargs['instance'].pk:
@@ -762,12 +814,15 @@ def geometry_pre_save(cls, pre_save_geom_values):
return geom_pre_save
pre_save_marker_values = {}
+
+
def marker_pre_save(sender, **kwargs):
if not kwargs['instance']:
return
geometry_pre_save(Marker, pre_save_marker_values)(sender, **kwargs)
pre_save.connect(marker_pre_save, sender=Marker)
+
def geometry_post_save(pre_save_geom_values):
def geom_post_save(sender, **kwargs):
if not kwargs['instance'] \
@@ -785,18 +840,21 @@ def geometry_post_save(pre_save_geom_values):
return
if instance.modified_since_import:
return
- if [key for key in pre if pre not in ('import_version',
- 'modified_since_import') and
- getattr(instance, key) != pre[key]]:
+ if [key for key in pre if pre not in (
+ 'import_version', 'modified_since_import') and
+ getattr(instance, key) != pre[key]]:
instance.modified_since_import = True
instance.save()
return geom_post_save
+
+
def marker_post_save(sender, **kwargs):
if not kwargs['instance'] or kwargs['created']:
return
geometry_post_save(pre_save_marker_values)(sender, **kwargs)
post_save.connect(marker_post_save, sender=Marker)
+
class MultimediaType(models.Model):
MEDIA_TYPES = (('A', _(u"Audio")),
('V', _(u"Video")),
@@ -832,25 +890,27 @@ class MultimediaType(models.Model):
return tuples
IFRAME_LINKS = {
- 'youtube':((re.compile(r'youtube.com\/watch\?[A-Za-z0-9_\-\=\&]*v=([A-Za-z0-9_-]*)[A-Za-z0-9_\-\=\&]*'),
- re.compile(r'youtu.be\/([A-Za-z0-9_-]*)'),
- re.compile(r'youtube.com\/embed\/([A-Za-z0-9_-]*)')),
- "http://www.youtube.com/embed/%s"),
- 'dailymotion':(
+ 'youtube': ((re.compile(r'youtube.com\/watch\?[A-Za-z0-9_\-\=\&]*v='
+ r'([A-Za-z0-9_-]*)[A-Za-z0-9_\-\=\&]*'),
+ re.compile(r'youtu.be\/([A-Za-z0-9_-]*)'),
+ re.compile(r'youtube.com\/embed\/([A-Za-z0-9_-]*)')),
+ "http://www.youtube.com/embed/%s"),
+ 'dailymotion': (
(re.compile(r'dailymotion.com/video/([A-Za-z0-9]*)_[A-Za-z0-9_-]*'),
re.compile(r'dailymotion.com/embed/video/([A-Za-z0-9]*)'),
re.compile("http://www.dailymotion.com/embed/video/%s")),
- 'http://www.dailymotion.com/embed/video/%s'),
- 'vimeo':((re.compile(r'vimeo.com/video/([A-Za-z0-9]*)'),
- re.compile(r'vimeo.com/([A-Za-z0-9]*)'),),
+ 'http://www.dailymotion.com/embed/video/%s'),
+ 'vimeo': ((re.compile(r'vimeo.com/video/([A-Za-z0-9]*)'),
+ re.compile(r'vimeo.com/([A-Za-z0-9]*)'),),
"http://player.vimeo.com/video/%s")
}
+
class MultimediaExtension(models.Model):
name = models.CharField(_(u"Extension name"), max_length=6)
- multimedia_type = models.ForeignKey(MultimediaType,
- verbose_name=_(u"Associated multimedia type"),
- related_name='extensions')
+ multimedia_type = models.ForeignKey(
+ MultimediaType, verbose_name=_(u"Associated multimedia type"),
+ related_name='extensions')
class Meta:
verbose_name = _(u"Multimedia extension")
@@ -859,13 +919,15 @@ class MultimediaExtension(models.Model):
def __unicode__(self):
return self.name
+
class MultimediaFile(models.Model):
name = models.CharField(_(u"Name"), max_length=150)
url = models.URLField(_(u"Url"), max_length=200)
order = models.IntegerField(_(u"Order"), default=1)
multimedia_type = models.ForeignKey(MultimediaType, blank=True, null=True)
- miniature = models.BooleanField(_(u"Display inside the description?"),
- default=settings.CHIMERE_MINIATURE_BY_DEFAULT)
+ miniature = models.BooleanField(
+ _(u"Display inside the description?"),
+ default=settings.CHIMERE_MINIATURE_BY_DEFAULT)
marker = models.ForeignKey(Marker, related_name='multimedia_files')
class Meta:
@@ -875,6 +937,7 @@ class MultimediaFile(models.Model):
def __unicode__(self):
return self.name or u""
+
def multimediafile_post_save(sender, **kwargs):
if not kwargs['instance'] or not kwargs['created']:
return
@@ -886,7 +949,7 @@ def multimediafile_post_save(sender, **kwargs):
res, embeded_url = IFRAME_LINKS[mm_type]
if [r for r in res if r.search(url)]:
multimedia_type = MultimediaType.objects.get(
- name__iexact=mm_type)
+ name__iexact=mm_type)
multimediafile.multimedia_type = multimedia_type
if not multimediafile.multimedia_type:
ext = url.split(".")[-1]
@@ -896,10 +959,12 @@ def multimediafile_post_save(sender, **kwargs):
else:
# default to an iframe
multimediafile.multimedia_type = \
- MultimediaType.objects.filter(name__iexact='iframe').all()[0]
+ MultimediaType.objects.filter(name__iexact='iframe')\
+ .all()[0]
# manage iframe of video providers
if multimediafile.multimedia_type.name.lower() in IFRAME_LINKS:
- regexps, lnk = IFRAME_LINKS[multimediafile.multimedia_type.name.lower()]
+ regexps, lnk = IFRAME_LINKS[
+ multimediafile.multimedia_type.name.lower()]
key = None
for regexp in regexps:
key = regexp.findall(multimediafile.url)
@@ -909,8 +974,9 @@ def multimediafile_post_save(sender, **kwargs):
if key:
multimediafile.url = lnk % key
- mfs = MultimediaFile.objects.filter(marker=multimediafile.marker).exclude(
- pk=multimediafile.pk).order_by('order')
+ mfs = MultimediaFile.objects.filter(marker=multimediafile.marker)\
+ .exclude(pk=multimediafile.pk)\
+ .order_by('order')
for idx, mf in enumerate(mfs.all()):
mf.order = idx + 1
mf.save()
@@ -918,18 +984,19 @@ def multimediafile_post_save(sender, **kwargs):
multimediafile.save()
post_save.connect(multimediafile_post_save, sender=MultimediaFile)
+
class PictureFile(models.Model):
name = models.CharField(_(u"Name"), max_length=150)
picture = models.ImageField(_(u"Image"), upload_to='pictures',
height_field='height', width_field='width')
height = models.IntegerField(_(u"Height"), blank=True, null=True)
width = models.IntegerField(_(u"Width"), blank=True, null=True)
- miniature = models.BooleanField(_(u"Display inside the description?"),
- default=settings.CHIMERE_MINIATURE_BY_DEFAULT)
- thumbnailfile = models.ImageField(_(u"Thumbnail"), upload_to='pictures',
- blank=True, null=True,
- height_field='thumbnailfile_height',
- width_field='thumbnailfile_width')
+ miniature = models.BooleanField(
+ _(u"Display inside the description?"),
+ default=settings.CHIMERE_MINIATURE_BY_DEFAULT)
+ thumbnailfile = models.ImageField(
+ _(u"Thumbnail"), upload_to='pictures', blank=True, null=True,
+ height_field='thumbnailfile_height', width_field='thumbnailfile_width')
thumbnailfile_height = models.IntegerField(_(u"Thumbnail height"),
blank=True, null=True)
thumbnailfile_width = models.IntegerField(_(u"Thumbnail width"),
@@ -944,6 +1011,7 @@ class PictureFile(models.Model):
verbose_name = _(u"Picture file")
verbose_name_plural = _(u"Picture files")
+
def scale_image(max_x, pair):
x, y = pair
new_y = (float(max_x) / x) * y
@@ -958,6 +1026,7 @@ IMAGE_EXIF_ORIENTATION_MAP = {
PYEXIV2_OLD_API = not hasattr(pyexiv2, 'ImageMetadata')
+
def picturefile_post_save(sender, **kwargs):
if not kwargs['instance']:
return
@@ -970,12 +1039,12 @@ def picturefile_post_save(sender, **kwargs):
metadata = pyexiv2.Image(filename)
metadata.readMetadata()
orientation = metadata['Exif.Image.Orientation'] \
- if 'Exif.Image.Orientation' in metadata.exifKeys() else None
+ if 'Exif.Image.Orientation' in metadata.exifKeys() else None
else:
metadata = pyexiv2.ImageMetadata(filename)
metadata.read()
orientation = metadata['Exif.Image.Orientation'].value \
- if 'Exif.Image.Orientation' in metadata else None
+ if 'Exif.Image.Orientation' in metadata else None
if orientation and orientation in IMAGE_EXIF_ORIENTATION_MAP \
and orientation > 1:
metadata['Exif.Image.Orientation'] = 1
@@ -993,7 +1062,7 @@ def picturefile_post_save(sender, **kwargs):
filehead, filetail = os.path.split(os.path.abspath(file.path))
basename, format = os.path.splitext(filetail)
basename = defaultfilters.slugify(basename)
- basename = re.sub(r'-','_', basename)
+ basename = re.sub(r'-', '_', basename)
miniature = basename + '_thumb.jpg'
filename = file.path
miniature_filename = os.path.join(filehead, miniature)
@@ -1005,12 +1074,10 @@ def picturefile_post_save(sender, **kwargs):
image_x, image_y = image.size
if settings.CHIMERE_THUMBS_SCALE_HEIGHT:
image_y, image_x = scale_image(
- settings.CHIMERE_THUMBS_SCALE_HEIGHT,
- (image_y, image_x))
+ settings.CHIMERE_THUMBS_SCALE_HEIGHT, (image_y, image_x))
elif settings.CHIMERE_THUMBS_SCALE_WIDTH:
image_x, image_y = scale_image(
- settings.CHIMERE_THUMBS_SCALE_WIDTH,
- (image_x, image_y))
+ settings.CHIMERE_THUMBS_SCALE_WIDTH, (image_x, image_y))
image.thumbnail([image_x, image_y], Image.ANTIALIAS)
temp_image = open(miniature_filename, 'w')
@@ -1027,8 +1094,8 @@ def picturefile_post_save(sender, **kwargs):
if not kwargs['created']:
return
- pfs = PictureFile.objects.filter(marker=picturefile.marker).exclude(
- pk=picturefile.pk).order_by('order')
+ pfs = PictureFile.objects.filter(marker=picturefile.marker)\
+ .exclude(pk=picturefile.pk).order_by('order')
for idx, pf in enumerate(pfs.all()):
pf.order = idx + 1
pf.save()
@@ -1036,12 +1103,13 @@ def picturefile_post_save(sender, **kwargs):
picturefile.save()
post_save.connect(picturefile_post_save, sender=PictureFile)
+
class RouteFile(models.Model):
name = models.CharField(_(u"Name"), max_length=150)
raw_file = models.FileField(_(u"Raw file (gpx or kml)"),
upload_to='route_files')
- simplified_file = models.FileField(_(u"Simplified file"),
- upload_to='route_files', blank=True, null=True)
+ simplified_file = models.FileField(
+ _(u"Simplified file"), upload_to='route_files', blank=True, null=True)
TYPE = (('K', _(u'KML')), ('G', _(u'GPX')))
file_type = models.CharField(max_length=1, choices=TYPE)
@@ -1058,7 +1126,7 @@ class RouteFile(models.Model):
return
input_name = settings.MEDIA_ROOT + self.raw_file.name
output_name = settings.MEDIA_ROOT + self.raw_file.name[:-4] + \
- "_simplified" + ".gpx"
+ "_simplified" + ".gpx"
cli_args = [settings.GPSBABEL, '-i']
if self.file_type == 'K':
cli_args.append('kml')
@@ -1070,7 +1138,7 @@ class RouteFile(models.Model):
p.wait()
if p.returncode:
print p.stderr.read()
- #logger.error(p.stderr.read())
+ # logger.error(p.stderr.read())
else:
self.simplified_file = File(open(output_name))
self.save()
@@ -1088,32 +1156,30 @@ class RouteFile(models.Model):
if not pt.tag.endswith('trkpt'):
continue
pts.append((pt.get("lon"), pt.get("lat")))
- geojson_tpl = u'{"type":"Feature", "geometry":{ "type": "LineString", '\
- '"coordinates":[%s]}}'
wkt_tpl = u'LINESTRING(%s)'
- return wkt_tpl % u','.join([u'%s %s' % (pt[0], pt[1]) \
- for pt in pts])
+ return wkt_tpl % u','.join([u'%s %s' % (pt[0], pt[1])
+ for pt in pts])
+
class Route(GeographicItem):
'''Route on the map
'''
- ref_item = models.ForeignKey("Route", blank=True, null=True,
- verbose_name=_(u"Reference route"), related_name='submited_route')
+ ref_item = models.ForeignKey(
+ "Route", blank=True, null=True, verbose_name=_(u"Reference route"),
+ related_name='submited_route')
route = RouteField(_(u"Route"),
srid=settings.CHIMERE_EPSG_DISPLAY_PROJECTION)
associated_file = models.ForeignKey(RouteFile, blank=True, null=True,
verbose_name=_(u"Associated file"))
- picture = models.ImageField(_(u"Image"), upload_to='upload', blank=True,
- null=True, height_field='height', width_field='width')
+ picture = models.ImageField(
+ _(u"Image"), upload_to='upload', blank=True, null=True,
+ height_field='height', width_field='width')
height = models.IntegerField(_(u"Height"), blank=True, null=True)
width = models.IntegerField(_(u"Width"), blank=True, null=True)
has_associated_marker = models.BooleanField(_(u"Has an associated marker"),
default=True)
objects = models.GeoManager()
- def __unicode__(self):
- return self.name
-
class Meta:
ordering = ('status', 'name')
verbose_name = _(u"Route")
@@ -1138,11 +1204,7 @@ class Route(GeographicItem):
setattr(self, attr_name, val)
if not hasattr(self, attr_name + '_set'):
setattr(self, attr_name + '_set',
- property_setter(self.__class__, pm))
-
- @property
- def geometry(self):
- return self.route.wkt
+ property_setter(self.__class__, pm))
@property
def geom_attr(self):
@@ -1151,8 +1213,10 @@ class Route(GeographicItem):
def get_init_multi(self):
if not self.associated_marker.count():
return []
- multis = [forms.model_to_dict(multi)
- for multi in self.associated_marker.all()[0].multimedia_files.all()]
+ multis = [
+ forms.model_to_dict(multi)
+ for multi in self.associated_marker.all()[0].multimedia_files.all()
+ ]
return multis
def get_init_picture(self):
@@ -1162,52 +1226,27 @@ class Route(GeographicItem):
for pict in self.associated_marker.all()[0].pictures.all()]
return picts
- def getProperty(self, propertymodel, safe=None):
- """Get the property of an associated property model.
- If safe set to True, verify if the property is available
- """
- if safe and not propertymodel.available:
- return
- try:
- property = Property.objects.get(propertymodel=propertymodel,
- marker=self)
- except Property.DoesNotExist:
- return
- return property
-
- def getProperties(self):
- """Get all the property availables
- """
- properties = []
- for pm in PropertyModel.objects.filter(available=True):
- property = self.getProperty(pm)
- if property:
- properties.append(property)
- return properties
-
def getGeoJSON(self, color="#000"):
'''Return a GeoJSON string
'''
if '#' not in color:
color = '#' + color
- attributes = {"type":"Feature",
- "geometry":json.loads(self.route.geojson),
- "properties":{"pk":self.id, "name":self.name,
- "color":color}}
+ attributes = {"type": "Feature",
+ "geometry": json.loads(self.route.geojson),
+ "properties": {"pk": self.id, "name": self.name,
+ "color": color}}
return json.dumps(attributes)
- def getTinyUrl(self):
- parameters = 'current_feature=%d&checked_categories=%s' % (self.id,
- self.categories[0].id)
- return TinyUrl.getUrnByParameters(parameters)
-
pre_save_route_values = {}
+
+
def route_pre_save(sender, **kwargs):
if not kwargs['instance']:
return
geometry_pre_save(Route, pre_save_route_values)(sender, **kwargs)
pre_save.connect(route_pre_save, sender=Route)
+
def route_post_save(sender, **kwargs):
if not kwargs['instance']:
return
@@ -1218,10 +1257,11 @@ def route_post_save(sender, **kwargs):
if instance.has_associated_marker:
marker_fields = [f.attname for f in Marker._meta.fields]
route_fields = [f.attname for f in Route._meta.fields]
- marker_dct = dict([(k, getattr(instance, k)) for k in marker_fields
- if k in route_fields and k not in ('id', 'ref_item_id')])
- marker_dct['point'] = "SRID=%d;POINT(%f %f)" % (instance.route.srid,
- instance.route[0][0], instance.route[0][1])
+ marker_dct = dict(
+ [(k, getattr(instance, k)) for k in marker_fields
+ if k in route_fields and k not in ('id', 'ref_item_id')])
+ marker_dct['point'] = "SRID=%d;POINT(%f %f)" % (
+ instance.route.srid, instance.route[0][0], instance.route[0][1])
marker, created = Marker.objects.get_or_create(route=instance,
defaults=marker_dct)
if not created:
@@ -1241,6 +1281,7 @@ def route_post_save(sender, **kwargs):
post_save.connect(route_post_save, sender=Route)
+
def sync_m2m_route(sender, **kwargs):
if kwargs['action'] not in ('post_add', 'post_clear', 'post_remove'):
return
@@ -1256,6 +1297,7 @@ def sync_m2m_route(sender, **kwargs):
marker.categories.add(cat)
m2m_changed.connect(sync_m2m_route, sender=Route.categories.through)
+
def getDateCondition():
'''
Return an SQL condition for apparition of dates
@@ -1263,9 +1305,9 @@ def getDateCondition():
if not settings.CHIMERE_DAYS_BEFORE_EVENT:
return ""
now = datetime.datetime.now().strftime('%Y-%m-%d')
- after = (datetime.datetime.now() + \
- datetime.timedelta(settings.CHIMERE_DAYS_BEFORE_EVENT)
- ).strftime('%Y-%m-%d')
+ after = (datetime.datetime.now() +
+ datetime.timedelta(settings.CHIMERE_DAYS_BEFORE_EVENT)).strftime(
+ '%Y-%m-%d')
date_condition = " and (%(alias)s.start_date is null or "
date_condition += "(%(alias)s.start_date >= '" + now + "' and "
date_condition += "%(alias)s.start_date <='" + after + "')"
@@ -1273,6 +1315,7 @@ def getDateCondition():
date_condition += "%(alias)s.end_date >='" + now + "')) "
return date_condition
+
class AggregatedRoute(models.Model):
'''
Database view for aggregated routes
@@ -1280,6 +1323,7 @@ class AggregatedRoute(models.Model):
route = models.MultiLineStringField()
subcategory = models.ForeignKey(SubCategory)
status = models.CharField(_(u"Status"), max_length=1, choices=STATUS)
+
class Meta:
managed = False
db_table = 'chimere_aggregated_routes'
@@ -1289,11 +1333,51 @@ class AggregatedRoute(models.Model):
'''
if '#' not in color:
color = '#' + color
- attributes = {'color':color, 'geometry':json.loads(self.route.geojson),
- 'type':"Feature", "properties":{"pk": self.id,
- "name": u'Aggregated route',}}
+ attributes = {
+ 'color': color, 'geometry': json.loads(self.route.geojson),
+ 'type': "Feature", "properties": {
+ "pk": self.id, "name": u'Aggregated route'}}
return json.dumps(attributes)
+
+class Polygon(GeographicItem):
+ '''Polygon on the map
+ '''
+ ref_item = models.ForeignKey(
+ "Polygon", blank=True, null=True, verbose_name=_(u"Reference polygon"),
+ related_name='submited_polygon')
+ polygon = PolygonField(
+ _(u"Polygon"), srid=settings.CHIMERE_EPSG_DISPLAY_PROJECTION)
+ picture = models.ImageField(
+ _(u"Image"), upload_to='upload', blank=True, null=True,
+ height_field='height', width_field='width')
+ height = models.IntegerField(_(u"Height"), blank=True, null=True)
+ width = models.IntegerField(_(u"Width"), blank=True, null=True)
+ objects = models.GeoManager()
+
+ class Meta:
+ ordering = ('status', 'name')
+ verbose_name = _(u"Polygon")
+
+ @property
+ def geom_attr(self):
+ return 'polygon'
+
+ def getGeoJSON(self, color="#000", inner_color='#0F0'):
+ '''Return a GeoJSON string
+ '''
+ if '#' not in color:
+ color = '#' + color
+ if '#' not in inner_color:
+ color = '#' + inner_color
+ attributes = {"type": "Feature",
+ "geometry": json.loads(self.route.geojson),
+ "properties": {"pk": self.id, "name": self.name,
+ "color": color,
+ "inner_color": inner_color}}
+ return json.dumps(attributes)
+
+
class SimplePoint:
"""
Point in the map (not in the database)
@@ -1301,6 +1385,7 @@ class SimplePoint:
def __init__(self, x, y):
self.x, self.y = x, y
+
class SimpleArea:
"""
Rectangular area of a map (not in the database)
@@ -1336,7 +1421,7 @@ class SimpleArea:
for subcat in subcats:
subcategory_pks.append(unicode(subcat.pk))
if filter_available:
- wheres += ['subcat.available = TRUE', 'cat.available = TRUE']
+ wheres += ['subcat.available = TRUE', 'cat.available = TRUE']
wheres += ['subcat.id in (%s)' % ",".join(subcategory_pks)]
where = " where " + " and ".join(wheres) if wheres else ""
@@ -1346,13 +1431,13 @@ class SimpleArea:
elif status:
equal_status = " in ('%s')" % "','".join(status)
area = u"ST_GeometryFromText('POLYGON((%f %f,%f %f,%f %f,%f %f, %f %f"\
- u"))', %d)" % (self.upper_left_corner.x, self.upper_left_corner.y,
- self.lower_right_corner.x, self.upper_left_corner.y,
- self.lower_right_corner.x, self.lower_right_corner.y,
- self.upper_left_corner.x, self.lower_right_corner.y,
- self.upper_left_corner.x, self.upper_left_corner.y,
- settings.CHIMERE_EPSG_DISPLAY_PROJECTION
- )
+ u"))', %d)" % (
+ self.upper_left_corner.x, self.upper_left_corner.y,
+ self.lower_right_corner.x, self.upper_left_corner.y,
+ self.lower_right_corner.x, self.lower_right_corner.y,
+ self.upper_left_corner.x, self.lower_right_corner.y,
+ self.upper_left_corner.x, self.upper_left_corner.y,
+ settings.CHIMERE_EPSG_DISPLAY_PROJECTION)
date_condition = getDateCondition()
sql_main = '''select subcat.id as id, subcat.category_id as category_id,
subcat.name as name, subcat.available as available,
@@ -1364,10 +1449,10 @@ class SimpleArea:
inner join chimere_marker mark on ST_Contains(%s, mark.point)''' % area
if equal_status:
sql += ' and mark.status' + equal_status
- sql += date_condition % {'alias':'mark'}
+ sql += date_condition % {'alias': 'mark'}
sql += '''
- inner join chimere_marker_categories mc on mc.subcategory_id=subcat.id and
- mc.marker_id=mark.id'''
+ inner join chimere_marker_categories mc on mc.subcategory_id=subcat.id
+ and mc.marker_id=mark.id'''
sql += where
subcats = set(SubCategory.objects.raw(sql))
sql = sql_main + '''
@@ -1375,17 +1460,18 @@ class SimpleArea:
ST_Contains(%s, rt.route))''' % (area, area)
if equal_status:
sql += ' and rt.status' + equal_status
- sql += date_condition % {'alias':'rt'}
+ sql += date_condition % {'alias': 'rt'}
sql += '''
- inner join chimere_route_categories rc on rc.subcategory_id=subcat.id and
- rc.route_id=rt.id'''
+ inner join chimere_route_categories rc on rc.subcategory_id=subcat.id
+ and rc.route_id=rt.id'''
sql += where
- # subcats.union(set(SubCategory.objects.raw(sql)))
+ # subcats.union(set(SubCategory.objects.raw(sql)))
# set union behave strangely. Doing it manualy...
for c in set(SubCategory.objects.raw(sql)):
subcats.add(c)
return subcats
+
class Layer(models.Model):
name = models.CharField(_(u"Name"), max_length=150)
layer_code = models.TextField(_(u"Layer code"), max_length=300)
@@ -1396,6 +1482,7 @@ class Layer(models.Model):
class Meta:
verbose_name = _("Layer")
+
class Area(models.Model, SimpleArea):
"""Rectangular area of the map
"""
@@ -1406,25 +1493,29 @@ class Area(models.Model, SimpleArea):
null=True)
order = models.IntegerField(_(u"Order"), unique=True)
available = models.BooleanField(_(u"Available"))
- upper_left_corner = models.PointField(_(u"Upper left corner"),
- default='POINT(0 0)', srid=settings.CHIMERE_EPSG_DISPLAY_PROJECTION)
- lower_right_corner = models.PointField(_(u"Lower right corner"),
- default='POINT(0 0)', srid=settings.CHIMERE_EPSG_DISPLAY_PROJECTION)
- default = models.NullBooleanField(_(u"Default area"),
- help_text=_(u"Only one area is set by default"))
+ upper_left_corner = models.PointField(
+ _(u"Upper left corner"), default='POINT(0 0)',
+ srid=settings.CHIMERE_EPSG_DISPLAY_PROJECTION)
+ lower_right_corner = models.PointField(
+ _(u"Lower right corner"), default='POINT(0 0)',
+ srid=settings.CHIMERE_EPSG_DISPLAY_PROJECTION)
+ default = models.NullBooleanField(
+ _(u"Default area"), help_text=_(u"Only one area is set by default"))
layers = SelectMultipleField(Layer, related_name='areas',
through='AreaLayers', blank=True)
- default_subcategories = SelectMultipleField(SubCategory, blank=True,
- verbose_name=_(u"Sub-categories checked by default"))
+ default_subcategories = SelectMultipleField(
+ SubCategory, blank=True,
+ verbose_name=_(u"Sub-categories checked by default"))
dynamic_categories = models.NullBooleanField(
_(u"Sub-categories dynamicaly displayed"),
- help_text=_(u"If checked, categories are only displayed in the menu if "
- u"they are available on the current extent."))
- subcategories = SelectMultipleField(SubCategory, related_name='areas',
- blank=True, db_table='chimere_subcategory_areas',
- verbose_name=_(u"Restricted to theses sub-categories"),
- help_text=_(u"If no sub-category is set all sub-categories are "
- u"available"))
+ help_text=_(u"If checked, categories are only displayed in the menu "
+ u"if they are available on the current extent."))
+ subcategories = SelectMultipleField(
+ SubCategory, related_name='areas',
+ blank=True, db_table='chimere_subcategory_areas',
+ verbose_name=_(u"Restricted to theses sub-categories"),
+ help_text=_(u"If no sub-category is set all sub-categories are "
+ u"available"))
external_css = models.URLField(_(u"Link to an external CSS"), blank=True,
null=True)
restrict_to_extent = models.BooleanField(_(u"Restrict to the area extent"),
@@ -1446,13 +1537,13 @@ class Area(models.Model, SimpleArea):
def getWkt(self):
return "SRID=%d;POLYGON((%f %f,%f %f,%f %f,%f %f, %f %f))" % (
- settings.CHIMERE_EPSG_DISPLAY_PROJECTION,
- self.upper_left_corner.x, self.upper_left_corner.y,
- self.lower_right_corner.x, self.upper_left_corner.y,
- self.lower_right_corner.x, self.lower_right_corner.y,
- self.upper_left_corner.x, self.lower_right_corner.y,
- self.upper_left_corner.x, self.upper_left_corner.y,
- )
+ settings.CHIMERE_EPSG_DISPLAY_PROJECTION,
+ self.upper_left_corner.x, self.upper_left_corner.y,
+ self.lower_right_corner.x, self.upper_left_corner.y,
+ self.lower_right_corner.x, self.lower_right_corner.y,
+ self.upper_left_corner.x, self.lower_right_corner.y,
+ self.upper_left_corner.x, self.upper_left_corner.y,
+ )
def getIncludeMarker(self):
"""
@@ -1466,13 +1557,22 @@ class Area(models.Model, SimpleArea):
"""
return Q(route__contained=self.getWkt())
+ def getIncludePolygon(self):
+ """
+ Get the sql statement for the test if the route is included in the area
+ """
+ return Q(polygon__contained=self.getWkt())
+
pre_save_area_values = {}
+
+
def area_pre_save(sender, **kwargs):
if not kwargs['instance']:
return
geometry_pre_save(Area, pre_save_area_values)(sender, **kwargs)
pre_save.connect(area_pre_save, sender=Area)
+
def area_post_save(sender, **kwargs):
if not kwargs['instance']:
return
@@ -1486,7 +1586,7 @@ def area_post_save(sender, **kwargs):
old_urn, old_name = area.urn, area.name
if area.pk in pre_save_area_values:
old_urn, old_name = pre_save_area_values[area.pk]
- perm, old_groups, old_users = None, [], []
+ perm = None
if area.urn != old_urn:
oldmnemo = 'change_area_' + old_urn
old_perm = Permission.objects.filter(codename=oldmnemo)
@@ -1502,7 +1602,7 @@ def area_post_save(sender, **kwargs):
lbl = "Can change " + area.name
if not perm.count():
content_type, created = ContentType.objects.get_or_create(
- app_label="chimere", model="area")
+ app_label="chimere", model="area")
perm = Permission(name=lbl, content_type_id=content_type.id,
codename=mnemo)
perm.save()
@@ -1529,13 +1629,14 @@ def area_post_save(sender, **kwargs):
('chimere', 'multimediafile'),
('chimere', 'picturefile'),
('chimere', 'routefile')):
- ct, created = ContentType.objects.get_or_create(app_label=app_label,
- model=model)
+ ct, created = ContentType.objects.get_or_create(
+ app_label=app_label, model=model)
for p in Permission.objects.filter(content_type=ct).all():
group.permissions.add(p)
post_save.connect(area_post_save, sender=Area)
+
def get_areas_for_user(user):
"""
Getting subcats for a specific user
@@ -1552,12 +1653,14 @@ def get_areas_for_user(user):
pass
return areas
+
def get_users_by_area(area):
if not area:
return []
- perm = 'change_area_'+area.urn
- return User.objects.filter(Q(groups__permissions__codename=perm)|
- Q(user_permissions__codename=perm)).all()
+ perm = 'change_area_' + area.urn
+ return User.objects.filter(Q(groups__permissions__codename=perm) |
+ Q(user_permissions__codename=perm)).all()
+
class AreaLayers(models.Model):
area = models.ForeignKey(Area)
@@ -1570,6 +1673,7 @@ class AreaLayers(models.Model):
verbose_name = _("Layers")
verbose_name_plural = _("Layers")
+
class PropertyModel(models.Model):
'''Model for a property
'''
@@ -1577,10 +1681,11 @@ class PropertyModel(models.Model):
order = models.IntegerField(_(u"Order"))
available = models.BooleanField(_(u"Available"))
mandatory = models.BooleanField(_(u"Mandatory"))
- subcategories = SelectMultipleField(SubCategory, related_name='properties',
- blank=True, verbose_name=_(u"Restricted to theses sub-categories"),
- help_text=_(u"If no sub-category is set all the property applies to all "
- u"sub-categories"))
+ subcategories = SelectMultipleField(
+ SubCategory, related_name='properties',
+ blank=True, verbose_name=_(u"Restricted to theses sub-categories"),
+ help_text=_(u"If no sub-category is set all the property applies to "
+ u"all sub-categories"))
TYPE = (('T', _('Text')),
('L', _('Long text')),
('P', _('Password')),
@@ -1588,23 +1693,25 @@ class PropertyModel(models.Model):
('C', _("Choices")),
('B', _("Boolean")),
)
- TYPE_WIDGET = {'T':forms.TextInput,
- 'L':TextareaWidget,
- 'P':forms.PasswordInput,
- 'D':DatePickerWidget,
- 'C':forms.Select,
- 'B':forms.CheckboxInput,
+ TYPE_WIDGET = {'T': forms.TextInput,
+ 'L': TextareaWidget,
+ 'P': forms.PasswordInput,
+ 'D': DatePickerWidget,
+ 'C': forms.Select,
+ 'B': forms.CheckboxInput,
}
type = models.CharField(_(u"Type"), max_length=1, choices=TYPE)
- def __unicode__(self):
- return self.name
+
class Meta:
ordering = ('order',)
verbose_name = _("Property model")
+ def __unicode__(self):
+ return self.name
+
def getAttrName(self):
attr_name = defaultfilters.slugify(self.name)
- attr_name = re.sub(r'-','_', attr_name)
+ attr_name = re.sub(r'-', '_', attr_name)
return attr_name
def getNamedId(self):
@@ -1612,6 +1719,7 @@ class PropertyModel(models.Model):
'''
return 'property_%d_%d' % (self.order, self.id)
+
class PropertyModelChoice(models.Model):
'''Choices for property model
'''
@@ -1619,12 +1727,14 @@ class PropertyModelChoice(models.Model):
verbose_name=_(u"Property model"))
value = models.CharField(_(u"Value"), max_length=150)
available = models.BooleanField(_(u"Available"), default=True)
- def __unicode__(self):
- return unicode(self.value)
class Meta:
verbose_name = _(u"Model property choice")
+ def __unicode__(self):
+ return unicode(self.value)
+
+
class Property(models.Model):
'''Property for a POI
'''
@@ -1632,13 +1742,14 @@ class Property(models.Model):
propertymodel = models.ForeignKey(PropertyModel,
verbose_name=_(u"Property model"))
value = models.TextField(_(u"Value"))
+
def __unicode__(self):
if self.propertymodel.type == 'C':
if not self.value:
return ''
try:
return unicode(PropertyModelChoice.objects.get(
- pk=self.value).value)
+ pk=self.value).value)
except (self.DoesNotExist, ValueError):
return ""
return unicode(self.value)
@@ -1650,7 +1761,8 @@ class Property(models.Model):
def python_value(self):
if self.propertymodel.type == 'D':
try:
- return datetime.date(*[int(val) for val in self.value.split('-')])
+ return datetime.date(*[int(val)
+ for val in self.value.split('-')])
except:
return ""
if self.propertymodel.type == 'C' and self.value:
@@ -1660,4 +1772,3 @@ class Property(models.Model):
return None
else:
return self.value
-