diff options
| 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 |
| commit | 63afe4e84cd3be5284a7126264c06ce87d191bc0 (patch) | |
| tree | 1ba8afc27b5aee7cdfb1d4abcde142b260c635b0 /chimere/main | |
| parent | f65df4be0383b60b6a500f76f6405a6c5621df23 (diff) | |
| parent | 00697996e885044314cc297b72aaa86d69d2a219 (diff) | |
| download | Chimè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.py | 14 | ||||
| -rw-r--r-- | chimere/main/admin.py | 18 | ||||
| -rw-r--r-- | chimere/main/forms.py | 50 | ||||
| -rw-r--r-- | chimere/main/models.py | 121 | ||||
| -rw-r--r-- | chimere/main/views.py | 47 | ||||
| -rw-r--r-- | chimere/main/widgets.py | 45 |
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) + |
