summaryrefslogtreecommitdiff
path: root/chimere/main
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@peacefrogs.net>2010-11-20 02:52:28 +0100
committerÉtienne Loks <etienne.loks@peacefrogs.net>2010-11-20 02:52:28 +0100
commit63afe4e84cd3be5284a7126264c06ce87d191bc0 (patch)
tree1ba8afc27b5aee7cdfb1d4abcde142b260c635b0 /chimere/main
parentf65df4be0383b60b6a500f76f6405a6c5621df23 (diff)
parent00697996e885044314cc297b72aaa86d69d2a219 (diff)
downloadChimère-63afe4e84cd3be5284a7126264c06ce87d191bc0.tar.bz2
Chimère-63afe4e84cd3be5284a7126264c06ce87d191bc0.zip
Merge branch 'master' into carte-ouverte
Conflicts: .gitignore chimere/main/actions.py chimere/urls.py
Diffstat (limited to 'chimere/main')
-rw-r--r--chimere/main/actions.py14
-rw-r--r--chimere/main/admin.py18
-rw-r--r--chimere/main/forms.py50
-rw-r--r--chimere/main/models.py121
-rw-r--r--chimere/main/views.py47
-rw-r--r--chimere/main/widgets.py45
6 files changed, 225 insertions, 70 deletions
diff --git a/chimere/main/actions.py b/chimere/main/actions.py
index aa817c1..3711234 100644
--- a/chimere/main/actions.py
+++ b/chimere/main/actions.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-# Copyright (C) 2008 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet>
+# Copyright (C) 2008-2010 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as
@@ -23,7 +23,7 @@ Actions available in the main interface
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth import models
-from chimere.settings import EXTRA_URL, EMAIL_HOST
+from chimere.settings import EXTRA_URL, EMAIL_HOST, INSTALLED_APPS
class Action:
def __init__(self, id, path, label):
@@ -33,7 +33,13 @@ actions = [(Action('view', '', _('View')), []),
(Action('contribute', 'edit', _('Contribute')),
(Action('edit', 'edit', _('Add a new point of interest')),
Action('edit_route', 'edit_route', _('Add a new route'))),
- ),
- (Action('charte', 'charte', _('Charte')), []),]
+ ),]
+
+if 'chimere.rss' in INSTALLED_APPS:
+ actions.append((Action('rss', 'rss', _('RSS feeds')), []))
+
+actions.append((Action('charte', 'charte', _('Charte')), []))
+
if EMAIL_HOST:
actions.append((Action('contact', 'contact', _('Contact us')), []),)
+
diff --git a/chimere/main/admin.py b/chimere/main/admin.py
index f63daa1..ea79f7a 100644
--- a/chimere/main/admin.py
+++ b/chimere/main/admin.py
@@ -21,6 +21,7 @@
Settings for administration pages
"""
+from chimere import settings
from chimere.main.models import Category, Icon, SubCategory, Marker, \
PropertyModel, News, Route, Area, ColorTheme, Color
from chimere.main.forms import MarkerAdminForm, RouteAdminForm, AreaAdminForm,\
@@ -47,8 +48,11 @@ class MarkerAdmin(admin.ModelAdmin):
Specialized the Point field.
"""
search_fields = ("name",)
- list_display = ('name', 'subcategory', 'status')
- list_filter = ('status', 'subcategory')
+ list_display = ('name', 'status')
+ list_filter = ('status', 'categories')
+ exclude = ['height', 'width']
+ if 'chimere.rss' in settings.INSTALLED_APPS:
+ exclude.append('available_date')
form = MarkerAdminForm
def queryset(self, request):
@@ -68,8 +72,9 @@ class RouteAdmin(admin.ModelAdmin):
Specialized the Route field.
"""
search_fields = ("name",)
- list_display = ('name', 'subcategory', 'status')
- list_filter = ('status', 'subcategory')
+ list_display = ('name', 'status')
+ list_filter = ('status', 'categories')
+ exclude = ['height', 'width']
form = RouteAdminForm
def queryset(self, request):
@@ -118,10 +123,13 @@ class ColorInline(admin.TabularInline):
class ColorThemeAdmin(admin.ModelAdmin):
inlines = [ColorInline,]
+class IconAdmin(admin.ModelAdmin):
+ exclude = ['height', 'width']
+
# register of differents database fields
admin.site.register(News, NewsAdmin)
admin.site.register(Category, CategoryAdmin)
-admin.site.register(Icon)
+admin.site.register(Icon, IconAdmin)
admin.site.register(SubCategory, SubCategoryAdmin)
admin.site.register(Marker, MarkerAdmin)
admin.site.register(Route, RouteAdmin)
diff --git a/chimere/main/forms.py b/chimere/main/forms.py
index f2490da..11b1d99 100644
--- a/chimere/main/forms.py
+++ b/chimere/main/forms.py
@@ -24,6 +24,7 @@ from django import forms
from django.contrib.gis.db import models
from django.utils.translation import ugettext as _
from django.contrib.auth.models import User, Permission, ContentType
+from django.contrib.admin.widgets import AdminDateWidget
from django.core.mail import EmailMessage, BadHeaderError
from chimere import settings
@@ -32,6 +33,22 @@ from chimere.main.models import Marker, Route, PropertyModel, Property, Area,\
News, Category, SubCategory
from chimere.main.widgets import AreaField, PointField, TextareaWidget
+from datetime import timedelta, datetime, tzinfo
+
+ZERO = timedelta(0)
+
+class UTC(tzinfo):
+ """UTC time zone"""
+
+ def utcoffset(self, dt):
+ return ZERO
+
+ def tzname(self, dt):
+ return settings.TIME_ZONE
+
+ def dst(self, dt):
+ return ZERO
+
def notifyStaff(subject, body, sender=None):
if not settings.EMAIL_HOST:
return
@@ -51,7 +68,7 @@ def notifyStaff(subject, body, sender=None):
return True
def notifySubmission(geo_object):
- category = unicode(geo_object.subcategory)
+ category = u" - ".join([unicode(cat) for cat in geo_object.categories.all()])
subject = u'%s %s' % (_(u"New submission for"), category)
message = _(u'The new item "%s" has been submited in the category: ') % \
geo_object.name + category
@@ -111,6 +128,22 @@ required=False)' % (property.order, property.id, property.name,
else:
keys['initial'] = property_dct
super(MarkerAdminForm, self).__init__(*args, **keys)
+ if settings.DAYS_BEFORE_EVENT:
+ self.fields['start_date'].widget = AdminDateWidget()
+ self.fields['end_date'].widget = AdminDateWidget()
+
+ def clean(self):
+ '''
+ Verify that a start date is provided when an end date is set
+ '''
+ if not settings.DAYS_BEFORE_EVENT:
+ return self.cleaned_data
+ if self.cleaned_data['end_date'] and \
+ not self.cleaned_data['start_date']:
+ msg = _(u"End date has been set with no start date")
+ self._errors["end_date"] = self.error_class([msg])
+ del self.cleaned_data['end_date']
+ return self.cleaned_data
def save(self, *args, **keys):
"""
@@ -119,6 +152,10 @@ required=False)' % (property.order, property.id, property.name,
new_marker = super(MarkerAdminForm, self).save(*args, **keys)
if 'status' not in self.cleaned_data:
new_marker.status = 'S'
+ if new_marker.status == 'A':
+ tz = UTC()
+ new_marker.available_date = datetime.replace(datetime.utcnow(),
+ tzinfo=tz)
new_marker.save()
# save each property
for propertymodel in PropertyModel.objects.filter(available=True):
@@ -180,6 +217,9 @@ required=False)' % (property.order, property.id, property.name,
else:
keys['initial'] = property_dct
super(RouteAdminForm, self).__init__(*args, **keys)
+ if settings.DAYS_BEFORE_EVENT:
+ self.fields['start_date'].widget = AdminDateWidget()
+ self.fields['end_date'].widget = AdminDateWidget()
def save(self, *args, **keys):
"""
@@ -268,3 +308,11 @@ class AreaAdminForm(forms.ModelForm):
if perm:
perm[0].delete()
return new_area
+
+class AreaForm(AreaAdminForm):
+ """
+ Form for the edit page
+ """
+ class Meta:
+ model = Area
+
diff --git a/chimere/main/models.py b/chimere/main/models.py
index f633b3f..093918b 100644
--- a/chimere/main/models.py
+++ b/chimere/main/models.py
@@ -20,6 +20,8 @@
"""
Models description
"""
+from datetime import datetime, timedelta
+
from django.utils.translation import ugettext_lazy as _
from django.contrib.gis.db import models
@@ -27,8 +29,7 @@ from django.contrib.gis.gdal import SpatialReference
from django.contrib import admin
from chimere import settings
-from chimere.main.widgets import PointField, RouteField, \
- ManyToManyField_NoSyncdb
+from chimere.main.widgets import PointField, RouteField, SelectMultipleField
class News(models.Model):
"""News of the site
@@ -42,6 +43,7 @@ class News(models.Model):
return self.title
class Meta:
verbose_name = _("News")
+ verbose_name_plural = _("News")
class TinyUrl(models.Model):
"""Tinyfied version of permalink parameters
@@ -122,6 +124,8 @@ class Icon(models.Model):
name = models.CharField(_("Name"), max_length=150)
image = models.ImageField(_("Image"), upload_to='icons',
height_field='height', width_field='width')
+ height = models.IntegerField(_("Height"))
+ width = models.IntegerField(_("Width"))
def __unicode__(self):
return self.name
class Meta:
@@ -133,8 +137,7 @@ class SubCategory(models.Model):
category = models.ForeignKey(Category, verbose_name=_("Category"))
name = models.CharField(_("Name"), max_length=150)
available = models.BooleanField(_("Available"))
- areas = models.ManyToManyField('Area', related_name='areas',
- blank=True, null=True)
+ areas = SelectMultipleField('Area', related_name='areas', blank=True)
icon = models.ForeignKey(Icon, verbose_name=_("Icon"))
color_theme = models.ForeignKey(ColorTheme, verbose_name=_("Color theme"),
blank=True, null=True)
@@ -163,8 +166,8 @@ class SubCategory(models.Model):
if area_name:
area = Area.objects.get(urn=area_name)
# if there some restrictions with categories limit them
- if area.subcategories.count():
- sub_ids = [sub.id for sub in area.subcategories.all()]
+ if area.subcategory_set.count():
+ sub_ids = [sub.id for sub in area.subcategory_set.all()]
# if no area is defined for a category don't filter it
sub_ids += [sub.id for sub in subcategories
if not sub.areas.count()]
@@ -183,10 +186,12 @@ class Marker(models.Model):
'''Marker for a POI
'''
name = models.CharField(_("Name"), max_length=150)
- subcategory = models.ForeignKey(SubCategory, verbose_name=_("Subcategory"))
- point = PointField(_("Localisation"))
+ categories = SelectMultipleField(SubCategory)
+ point = PointField(_("Localisation"), srid=settings.EPSG_DISPLAY_PROJECTION)
picture = models.ImageField(_("Image"), upload_to='upload', blank=True,
- height_field='height', width_field='width')
+ null=True, height_field='height', width_field='width')
+ height = models.IntegerField(_("Height"), blank=True, null=True)
+ width = models.IntegerField(_("Width"), blank=True, null=True)
STATUS = (('S', _('Submited')),
('A', _('Available')),
('D', _('Disabled')),)
@@ -194,13 +199,23 @@ class Marker(models.Model):
for key, label in STATUS:
STATUS_DCT[key] = label
status = models.CharField(_("Status"), max_length=1, choices=STATUS)
+ if settings.DAYS_BEFORE_EVENT:
+ start_date = models.DateField(_("Start date"), blank=True, null=True,
+help_text=_("Not mandatory. Set it for dated item such as event. \
+Format YYYY-MM-DD"))
+ end_date = models.DateField(_("End date"), blank=True, null=True,
+help_text=_("Not mandatory. Set it only if you have a multi-day event. \
+Format YYYY-MM-DD"))
+ if 'chimere.rss' in settings.INSTALLED_APPS:
+ available_date = models.DateTimeField(_("Available Date"), blank=True,
+ null=True)
objects = models.GeoManager()
def __unicode__(self):
return self.name
class Meta:
- ordering = ('subcategory__category', 'subcategory', 'status', 'name')
+ ordering = ('status', 'name')
verbose_name = _("Point of interest")
def getLatitude(self):
@@ -236,31 +251,44 @@ class Marker(models.Model):
properties.append(property)
return properties
- def getGeoJSON(self):
+ def getGeoJSON(self, categories_id=[]):
'''Return a GeoJSON string
'''
- return """{"type":"Feature", "geometry":%(geometry)s, \
+ jsons = []
+ for cat in self.categories.all():
+ if categories_id and cat.id not in categories_id:
+ continue
+ jsons.append("""{"type":"Feature", "geometry":%(geometry)s, \
"properties":{"pk": %(id)d, "name": "%(name)s", \
"icon_path":"%(icon_path)s", "icon_width":%(icon_width)d, \
"icon_height":%(icon_height)d}}""" % {'id':self.id, 'name':self.name,
-'icon_path':self.subcategory.icon.image, 'geometry':self.point.geojson,
-'icon_width':self.subcategory.icon.image.width,
-'icon_height':self.subcategory.icon.image.height,}
+'icon_path':cat.icon.image, 'geometry':self.point.geojson,
+'icon_width':cat.icon.image.width, 'icon_height':cat.icon.image.height,})
+ return ",".join(jsons)
class Route(models.Model):
'''Route on the map
'''
name = models.CharField(_("Name"), max_length=150)
- subcategory = models.ForeignKey(SubCategory, verbose_name=_("Subcategory"))
- route = RouteField(_("Route"))
+ categories = SelectMultipleField(SubCategory)
+ route = RouteField(_("Route"), srid=settings.EPSG_DISPLAY_PROJECTION)
picture = models.ImageField(_("Image"), upload_to='upload', blank=True,
- height_field='height', width_field='width')
+ null=True, height_field='height', width_field='width')
+ height = models.IntegerField(_("Height"), blank=True, null=True)
+ width = models.IntegerField(_("Width"), blank=True, null=True)
STATUS = (('S', _('Submited')),
('A', _('Available')),
('D', _('Disabled')),)
STATUS_DCT = {}
for key, label in STATUS:
STATUS_DCT[key] = label
+ if settings.DAYS_BEFORE_EVENT:
+ start_date = models.DateField(_("Start date"), blank=True, null=True,
+help_text=_("Not mandatory. Set it for dated item such as event. \
+Format YYYY-MM-DD"))
+ end_date = models.DateField(_("End date"), blank=True, null=True,
+help_text=_("Not mandatory. Set it only if you have a multi-day event. \
+Format YYYY-MM-DD"))
status = models.CharField(_("Status"), max_length=1, choices=STATUS)
objects = models.GeoManager()
@@ -268,7 +296,7 @@ class Route(models.Model):
return self.name
class Meta:
- ordering = ('subcategory__category', 'subcategory', 'status', 'name')
+ ordering = ('status', 'name')
verbose_name = _("Route")
def getProperty(self, propertymodel, safe=None):
@@ -304,6 +332,22 @@ class Route(models.Model):
"color":"%(color)s"}}""" % {'id':self.id, 'name':self.name,
'color':color, 'geometry':self.route.geojson,}
+def getDateCondition():
+ '''
+ Return an SQL condition for apparition of dates
+ '''
+ if not settings.DAYS_BEFORE_EVENT:
+ return ""
+ now = datetime.now().strftime('%Y-%m-%d')
+ after = (datetime.now() + timedelta(settings.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 + "')"
+ date_condition += " or (%(alias)s.start_date <='" + now + "' and "
+ date_condition += "%(alias)s.end_date >='" + now + "') "
+ return date_condition
+
class SimplePoint:
"""
Point in the map (not in the database)
@@ -352,39 +396,35 @@ class SimpleArea:
self.upper_left_corner.x, self.upper_left_corner.y,
settings.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, subcat.icon_id as icon_id,
subcat.color_theme_id as color_theme_id, subcat.order as order,
subcat.item_type as item_type from main_subcategory subcat
inner join main_category cat on cat.id=subcat.category_id'''
sql = sql_main + '''
-inner join main_marker mark on mark.subcategory_id=subcat.id
- and ST_Contains(%s, mark.point)''' % area
+inner join main_marker mark on ST_Contains(%s, mark.point)''' % area
if equal_status:
sql += ' and mark.status' + equal_status
+ sql += date_condition % {'alias':'mark'}
+ sql += '''
+inner join main_marker_categories mc on mc.subcategory_id=subcat.id and
+mc.marker_id=mark.id'''
if filter_available:
sql += ' where subcat.available = TRUE and cat.available = TRUE'
- print sql
- # django > 1.1
- #subcats = SubCategory.objects.raw(sql)
- from django.db import connection, transaction
- cursor = connection.cursor()
- cursor.execute(sql, [])
- subcats = set()
- for r in cursor.fetchall():
- subcats.add(SubCategory.objects.get(id=r[0]))
+ subcats = set(SubCategory.objects.raw(sql))
sql = sql_main + '''
-inner join main_route rt on rt.subcategory_id=subcat.id
-and (ST_Intersects(%s, rt.route) or ST_Contains(%s, rt.route))''' % (area, area)
+inner join main_route rt on (ST_Intersects(%s, rt.route) or
+ST_Contains(%s, rt.route))''' % (area, area)
if equal_status:
sql += ' and rt.status' + equal_status
+ sql += date_condition % {'alias':'rt'}
+ sql += '''
+inner join main_route_categories rc on rc.subcategory_id=subcat.id and
+rc.route_id=rt.id'''
if filter_available:
sql += ' where subcat.available = TRUE and cat.available = TRUE'
- # django > 1.1
- #subcats += SubCategory.objects.raw(sql)
- cursor.execute(sql, [])
- for r in cursor.fetchall():
- subcats.add(SubCategory.objects.get(id=r[0]))
+ subcats.union(SubCategory.objects.raw(sql))
return subcats
class Area(models.Model, SimpleArea):
@@ -393,15 +433,12 @@ class Area(models.Model, SimpleArea):
name = models.CharField(_("Name"), max_length=150)
urn = models.SlugField(_("Area urn"), max_length=50, blank=True,
unique=True)
- subcategories = ManyToManyField_NoSyncdb(SubCategory,
- related_name='subcategories', blank=True, null=True,
- db_table=u'subcategory_areas')
order = models.IntegerField(_("Order"))
available = models.BooleanField(_("Available"))
upper_left_corner = models.PointField(_("Upper left corner"),
- default='POINT(0 0)')
+ default='POINT(0 0)', srid=settings.EPSG_DISPLAY_PROJECTION)
lower_right_corner = models.PointField(_("Lower right corner"),
- default='POINT(0 0)')
+ default='POINT(0 0)', srid=settings.EPSG_DISPLAY_PROJECTION)
objects = models.GeoManager()
def __unicode__(self):
diff --git a/chimere/main/views.py b/chimere/main/views.py
index cf8b1b7..91f398d 100644
--- a/chimere/main/views.py
+++ b/chimere/main/views.py
@@ -30,6 +30,7 @@ from django.template import loader
from django.http import HttpResponseRedirect, HttpResponse
from django.core import serializers
from django.utils.http import urlquote
+from django.db.models import Q
from chimere import settings
from chimere.main.actions import actions
@@ -136,6 +137,7 @@ def edit(request, area_name=""):
'error_message':'',
'map_layer':settings.MAP_LAYER,
'form':form,
+ 'dated':settings.DAYS_BEFORE_EVENT,
'extra_head':form.media,
'sub_categories':SubCategory.getAvailable(['M', 'B'],
area_name),
@@ -176,6 +178,7 @@ def editRoute(request, area_name=""):
'error_message':'',
'map_layer':settings.MAP_LAYER,
'form':form,
+ 'dated':settings.DAYS_BEFORE_EVENT,
'extra_head':form.media,
'sub_categories':SubCategory.getAvailable(['R', 'B'],
area_name),
@@ -252,12 +255,14 @@ def getDetail(request, area_name, marker_id):
if 'simple' in request.GET and request.GET['simple']:
response_dct['simple'] = True
parameters = u'current_feature=%s' % marker_id
- parameters += u"&checked_categories=%d" % marker.subcategory.id
+ parameters += u"&checked_categories=%s" % "_".join([str(m.id) \
+ for m in marker.categories.all()])
net_dct = getTinyfiedUrl(parameters, area_name)
share_networks = []
for network in settings.SHARE_NETWORKS:
share_networks.append((network[0], network[1] % net_dct, network[2]))
response_dct['share_networks'] = share_networks
+ response_dct['dated'] = settings.DAYS_BEFORE_EVENT and marker.start_date
return render_to_response('detail.html', response_dct)
def getDescriptionDetail(request, area_name, category_id):
@@ -272,6 +277,21 @@ def getDescriptionDetail(request, area_name, category_id):
response_dct['category'] = category
return render_to_response('category_detail.html', response_dct)
+def checkDate(q):
+ """
+ Filter a queryset to manage dates
+ """
+ if not settings.DAYS_BEFORE_EVENT:
+ return q
+ today = datetime.date.today()
+ after = today + datetime.timedelta(settings.DAYS_BEFORE_EVENT)
+
+ q = q & ( Q(start_date__isnull=True)
+ | Q(start_date__gte=today, start_date__lte=after)
+ | Q(start_date__lte=today, end_date__gte=today)
+ )
+ return q
+
def getGeoObjects(request, area_name, category_ids, status):
'''
Get the JSON for markers and routes
@@ -279,35 +299,38 @@ def getGeoObjects(request, area_name, category_ids, status):
if not status:
status = 'A'
status = status.split('_')
+ category_ids = category_ids.split('_')
try:
- query = Route.objects.filter(status__in=status,
- subcategory__in=category_ids.split('_'))
+ q = checkDate(Q(status__in=status, categories__in=category_ids))
+ query = Route.objects.filter(q)
except:
return HttpResponse('no results')
- query.order_by('subcategory')
+ query.order_by('categories')
routes = list(query)
jsons = []
current_cat, colors, idx = None, None, 0
for route in routes:
- if not current_cat or current_cat != route.subcategory:
+ c_cat = route.categories.all()[0]
+ if not current_cat or current_cat != c_cat:
idx = 0
- current_cat = route.subcategory
- colors = list(Color.objects.filter(color_theme=\
- route.subcategory.color_theme))
+ current_cat = c_cat
+ colors = list(Color.objects.filter(color_theme = c_cat.color_theme))
jsons.append(route.getGeoJSON(color=colors[idx % len(colors)].code))
idx += 1
try:
- query = Marker.objects.filter(status__in=status,
- subcategory__in=category_ids.split('_'))
+ q = checkDate(Q(status__in=status, categories__in=category_ids))
+ query = Marker.objects.filter(q)
except:
return HttpResponse('no results')
- jsons += [geo_object.getGeoJSON() for geo_object in list(query)]
+ category_ids = [int(cat_id) for cat_id in category_ids]
+ jsons += [geo_object.getGeoJSON(category_ids) for geo_object in list(query)]
if not jsons:
return HttpResponse('no results')
data = '{"type": "FeatureCollection", "features":[%s]}' % ",".join(jsons)
return HttpResponse(data)
-def getAvailableCategories(request, area_name=None, area=None, status='A', force=None):
+def getAvailableCategories(request, area_name=None, area=None, status='A',
+ force=None):
'''
Get categories for a designed area
'''
diff --git a/chimere/main/widgets.py b/chimere/main/widgets.py
index 4ad6475..9c53a6d 100644
--- a/chimere/main/widgets.py
+++ b/chimere/main/widgets.py
@@ -33,11 +33,6 @@ URL_OSM_CSS = ["http://www.openlayers.org/api/theme/default/style.css"]
URL_OSM_JS = ["http://www.openlayers.org/api/OpenLayers.js",
"http://www.openstreetmap.org/openlayers/OpenStreetMap.js"]
-class ManyToManyField_NoSyncdb(models.ManyToManyField):
- def __init__(self, *args, **kwargs):
- super(ManyToManyField_NoSyncdb, self).__init__(*args, **kwargs)
- self.creates_table = False
-
def getMapJS(area_name=''):
'''Variable initialization for drawing the map
'''
@@ -136,7 +131,7 @@ class PointField(models.PointField):
keys.update(defaults)
return super(PointField, self).formfield(**keys)
- def clean(self, value):
+ def clean(self, value, instance=None):
if len(value) != 2 and self.required:
raise ValidationError(_("Invalid point"))
return value
@@ -299,3 +294,41 @@ class AreaField(forms.MultiValueField):
if not data_list:
return None
return data_list
+
+class MultiSelectWidget(forms.SelectMultiple):
+ class Media:
+ css = {'all': (
+ settings.MEDIA_URL + 'jquery/bsmSelect/css/jquery.bsmselect.css',
+ settings.MEDIA_URL + 'jquery/css/jquery.bsmselect.custom.css',
+ )
+ }
+ js = (
+ settings.MEDIA_URL + 'jquery/jquery-1.4.4.min.js',
+ settings.MEDIA_URL + 'jquery/bsmSelect/js/jquery.bsmselect.js',
+ settings.MEDIA_URL + 'jquery/bsmSelect/js/jquery.bsmselect.compatibility.js',
+ )
+
+ def render(self, name, value, attrs=None):
+ rendered = super(MultiSelectWidget, self).render(name, value, attrs)
+ return mark_safe(rendered + u'''<hr class='spacer'/><script type="text/javascript">
+$.bsmSelect.conf['title'] = "%(title)s";
+$("#id_%(name)s").bsmSelect({
+ removeLabel: '<strong>X</strong>',
+ containerClass: 'bsmContainer',
+ listClass: 'bsmList-custom',
+ listItemClass: 'bsmListItem-custom',
+ listItemLabelClass: 'bsmListItemLabel-custom',
+ removeClass: 'bsmListItemRemove-custom'
+});
+</script>''' % {'name':name, 'title':_("Select...")})
+
+class SelectMultipleField(models.ManyToManyField):
+ '''
+ Set the widget for the category field
+ '''
+ def formfield(self, **keys):
+ self.help_text = ""
+ defaults = {'widget': MultiSelectWidget}
+ keys.update(defaults)
+ return super(SelectMultipleField, self).formfield(**keys)
+