--- /dev/null
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding model 'Location'
+ db.create_table('julian_location', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=255)),
+ ))
+ db.send_create_signal('julian', ['Location'])
+
+ # Adding model 'Event'
+ db.create_table('julian_event', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('start_date', self.gf('django.db.models.fields.DateField')()),
+ ('start_time', self.gf('django.db.models.fields.TimeField')(null=True, blank=True)),
+ ('end_date', self.gf('django.db.models.fields.DateField')()),
+ ('end_time', self.gf('django.db.models.fields.TimeField')(null=True, blank=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=255)),
+ ('slug', self.gf('django.db.models.fields.SlugField')(max_length=255, db_index=True)),
+ ('location_content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),
+ ('location_pk', self.gf('django.db.models.fields.TextField')()),
+ ('description', self.gf('philo.models.fields.TemplateField')()),
+ ('parent_event', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['julian.Event'], null=True, blank=True)),
+ ('owner', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+ ))
+ db.send_create_signal('julian', ['Event'])
+
+ # Adding M2M table for field tags on 'Event'
+ db.create_table('julian_event_tags', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('event', models.ForeignKey(orm['julian.event'], null=False)),
+ ('tag', models.ForeignKey(orm['philo.tag'], null=False))
+ ))
+ db.create_unique('julian_event_tags', ['event_id', 'tag_id'])
+
+ # Adding model 'Calendar'
+ db.create_table('julian_calendar', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=100)),
+ ('uuid', self.gf('django.db.models.fields.CharField')(unique=True, max_length=100)),
+ ))
+ db.send_create_signal('julian', ['Calendar'])
+
+ # Adding M2M table for field events on 'Calendar'
+ db.create_table('julian_calendar_events', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('calendar', models.ForeignKey(orm['julian.calendar'], null=False)),
+ ('event', models.ForeignKey(orm['julian.event'], null=False))
+ ))
+ db.create_unique('julian_calendar_events', ['calendar_id', 'event_id'])
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'Location'
+ db.delete_table('julian_location')
+
+ # Deleting model 'Event'
+ db.delete_table('julian_event')
+
+ # Removing M2M table for field tags on 'Event'
+ db.delete_table('julian_event_tags')
+
+ # Deleting model 'Calendar'
+ db.delete_table('julian_calendar')
+
+ # Removing M2M table for field events on 'Calendar'
+ db.delete_table('julian_calendar_events')
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'julian.calendar': {
+ 'Meta': {'object_name': 'Calendar'},
+ 'events': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'calendars'", 'symmetrical': 'False', 'to': "orm['julian.Event']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'uuid': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'})
+ },
+ 'julian.event': {
+ 'Meta': {'object_name': 'Event'},
+ 'description': ('philo.models.fields.TemplateField', [], {}),
+ 'end_date': ('django.db.models.fields.DateField', [], {}),
+ 'end_time': ('django.db.models.fields.TimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'location_content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'location_pk': ('django.db.models.fields.TextField', [], {}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'parent_event': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['julian.Event']", 'null': 'True', 'blank': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'start_date': ('django.db.models.fields.DateField', [], {}),
+ 'start_time': ('django.db.models.fields.TimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['philo.Tag']", 'null': 'True', 'blank': 'True'})
+ },
+ 'julian.location': {
+ 'Meta': {'object_name': 'Location'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+ },
+ 'philo.attribute': {
+ 'Meta': {'unique_together': "(('key', 'entity_content_type', 'entity_object_id'), ('value_content_type', 'value_object_id'))", 'object_name': 'Attribute'},
+ 'entity_content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'attribute_entity_set'", 'to': "orm['contenttypes.ContentType']"}),
+ 'entity_object_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'value_content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'attribute_value_set'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
+ 'value_object_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'})
+ },
+ 'philo.tag': {
+ 'Meta': {'object_name': 'Tag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'})
+ }
+ }
+
+ complete_apps = ['julian']
from django.conf import settings
-from django.contrib.localflavor.us.models import USStateField
-from django.contrib.contenttypes.generic import GenericForeignKey, GenericRelation
+from django.contrib.contenttypes.generic import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError
-from django.core.validators import RegexValidator, MinValueValidator, MaxValueValidator
+from django.core.validators import RegexValidator
from django.db import models
-from philo.contrib.julian.fields import USZipCodeField
-from philo.models.base import Tag, Entity, Titled
+from philo.models.base import Tag, Entity
from philo.models.fields import TemplateField
-from philo.utils import ContentTypeSubclassLimiter
-import datetime
+from philo.utils import ContentTypeRegistryLimiter
import re
FPI_REGEX = re.compile(r"(|\+//|-//)[^/]+//[^/]+//[A-Z]{2}")
-class Location(Entity):
- name = models.CharField(max_length=150, blank=True)
- description = models.TextField(blank=True)
-
- longitude = models.FloatField(blank=True, validators=[MinValueValidator(-180), MaxValueValidator(180)])
- latitude = models.FloatField(blank=True, validators=[MinValueValidator(-90), MaxValueValidator(90)])
-
- events = GenericRelation('Event')
-
- def clean(self):
- if not (self.name or self.description) or (self.longitude is None and self.latitude is None):
- raise ValidationError("Either a name and description or a latitude and longitude must be defined.")
-
- class Meta:
- abstract = True
+location_content_type_limiter = ContentTypeRegistryLimiter()
-_location_content_type_limiter = ContentTypeSubclassLimiter(Location)
+def register_location_model(model):
+ location_content_type_limiter.register_class(model)
-# TODO: Can we track when a building is open? Hmm...
-class Building(Location):
- """A building is a location with a street address."""
- address = models.CharField(max_length=255)
- city = models.CharField(max_length=150)
-
- class Meta:
- abstract = True
-
-
-_building_content_type_limiter = ContentTypeSubclassLimiter(Building)
+def unregister_location_model(model):
+ location_content_type_limiter.unregister_class(model)
-class USBuilding(Building):
- state = USStateField()
- zipcode = USZipCodeField()
+class Location(Entity):
+ name = models.CharField(max_length=255)
- class Meta:
- verbose_name = "Building (US)"
- verbose_name_plural = "Buildings (US)"
+ def __unicode__(self):
+ return self.name
-class Venue(Location):
- """A venue is a location inside a building"""
- building_content_type = models.ForeignKey(ContentType, limit_choices_to=_building_content_type_limiter)
- building_pk = models.TextField()
- building = GenericForeignKey('building_content_type', 'building_pk')
+register_location_model(Location)
class TimedModel(models.Model):
def is_all_day(self):
return self.start_time is None and self.end_time is None
+ def clean(self):
+ if bool(self.start_time) != bool(self.end_time):
+ raise ValidationError("A %s must have either a start time and an end time or neither.")
+
+ if self.start_date > self.end_date or self.start_date == self.end_date and self.start_time > self.end_time:
+ raise ValidationError("A %s cannot end before it starts." % self.__class__.__name__)
+
class Meta:
abstract = True
-class Event(Entity, Titled, TimedModel):
- location_content_type = models.ForeignKey(ContentType, limit_choices_to=_location_content_type_limiter)
+class Event(Entity, TimedModel):
+ name = models.CharField(max_length=255)
+ slug = models.SlugField(max_length=255)
+
+ location_content_type = models.ForeignKey(ContentType, limit_choices_to=location_content_type_limiter)
location_pk = models.TextField()
location = GenericForeignKey('location_content_type', 'location_pk')
parent_event = models.ForeignKey('self', blank=True, null=True)
owner = models.ForeignKey(getattr(settings, 'PHILO_PERSON_MODULE', 'auth.User'))
+
+ # TODO: Add uid - use as pk?
class Calendar(Entity):