Skip to content

Commit

Permalink
create_report() streamlines creation of related event & annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
sheppard committed May 29, 2013
1 parent c4054fa commit 9029fdf
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 6 deletions.
4 changes: 2 additions & 2 deletions contrib/qual/migrations/0001_initial.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def forwards(self, orm):
('event', self.gf('django.db.models.fields.related.ForeignKey')(to=Event)),
('entered', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
('user', self.gf('django.db.models.fields.related.ForeignKey')(to=User)),
('status', self.gf('django.db.models.fields.related.ForeignKey')(to=ReportStatus)),
('status', self.gf('django.db.models.fields.related.ForeignKey')(to=ReportStatus, null=True, blank=True)),
))
db.send_create_signal(u'qual', ['Report'])

Expand Down Expand Up @@ -204,7 +204,7 @@ def backwards(self, orm):
'entered': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'event': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reports'", 'to': u"orm['qual.Event']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['qual.ReportStatus']"}),
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['qual.ReportStatus']", 'null': 'True', 'blank': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
},
u'qual.reportstatus': {
Expand Down
47 changes: 44 additions & 3 deletions contrib/qual/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
for model in ('Site', 'Event', 'Report', 'ReportStatus')
}

VALID_REPORT_ORDER = getattr(settings, "WQ_VALID_REPORT_ORDER", ('-entered',))
# Base classes for Site-Event-Report-Attribute-Value pattern
# Extend these when swapping out default implementation (below)

Expand All @@ -16,14 +17,42 @@ class Meta:

class BaseEvent(models.NaturalKeyModel):
site = models.ForeignKey(MODELS['Site'])

@property
def valid_reports(self):
return self.reports.filter(status__is_valid=True).order_by(*VALID_REPORT_ORDER)

@property
def vals(self):
vals = {}
for report in reversed(self.valid_reports):
vals.update(report.vals)
return vals

class Meta:
abstract = True

class ReportManager(models.Manager):
def create_report(self, event_key, values, **kwargs):
Event = swapper.load_model('qual', 'Event')
kwargs['event'] = Event.objects.find(*event_key)
report = self.create(**kwargs)
report.vals = values
return report

class ValidReportManager(ReportManager):
def get_queryset(self):
qs = super(ValidReportManager, self)
return qs.filter(status__is_valid=True).order_by(*VALID_REPORT_ORDER)

class BaseReport(models.AnnotatedModel):
event = models.ForeignKey(MODELS['Event'])
event = models.ForeignKey(MODELS['Event'], related_name='reports')
entered = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL)
status = models.ForeignKey(MODELS['ReportStatus'])
status = models.ForeignKey(MODELS['ReportStatus'], null=True, blank=True)

objects = ReportManager()
valid_objects = ValidReportManager()

def __unicode__(self):
return "%s according to %s" % (self.event, self.user)
Expand All @@ -41,10 +70,15 @@ def __unicode__(self):
class Meta:
abstract = True

class ParameterManager(models.IdentifiedModelManager, models.AnnotationTypeManager):
pass

class BaseParameter(models.BaseAnnotationType, models.IdentifiedModel):
is_numeric = models.BooleanField()
units = models.CharField(max_length=50, null=True, blank=True)

objects = ParameterManager()

@property
def annotated_model(self):
return swapper.load_model('qual', 'Report')
Expand All @@ -63,10 +97,17 @@ class BaseResult(models.BaseAnnotation):

@property
def value(self):
if self.value_numeric is not None:
if self.type.is_numeric:
return self.value_numeric
return self.value_text

@value.setter
def value(self, val):
if self.type.is_numeric:
self.value_numeric = val
else:
self.value_text = val

class Meta:
abstract = True

Expand Down
34 changes: 33 additions & 1 deletion patterns/annotate/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,21 @@
ANNOTATIONTYPE_MODEL = swapper.is_swapped('annotate', 'AnnotationType') or 'AnnotationType'
ANNOTATION_MODEL = swapper.is_swapped('annotate', 'Annotation') or 'Annotation'

class AnnotationTypeManager(models.Manager):
def get_by_natural_key(self, name):
return self.get(name=name)

def resolve_names(self, *names):
resolved = {}
success = True
for name in names:
try:
resolved[name] = self.get_by_natural_key(name)
except self.model.DoesNotExist:
success = False
resolved[name] = None
return resolved, success

class BaseAnnotationType(models.Model):
name = models.CharField(max_length=255)
contenttype = models.ForeignKey(ContentType, null=True, blank=True)
Expand All @@ -16,6 +31,8 @@ class BaseAnnotationType(models.Model):
# (Useful for subclasses with a single target model)
annotated_model = None

objects = AnnotationTypeManager()

def __unicode__(self):
for f in self._meta.get_all_related_objects():
# Check for any linked subclasses as they may have a more
Expand All @@ -30,6 +47,9 @@ def __unicode__(self):
# Fall back to name
return self.name

def natural_key(self):
return (self.name,)

def clean(self, *args, **kwargs):
if self.annotated_model is not None:
self.contenttype = ContentType.objects.get_for_model(self.annotated_model)
Expand All @@ -52,7 +72,7 @@ def vals(self):

vals = {}
for annot in self.all():
vals[str(annot.type)] = annot.value
vals[annot.type.natural_key()[0]] = annot.value

setattr(self, '_vals', vals)
return vals
Expand Down Expand Up @@ -127,6 +147,18 @@ class AnnotatedModel(models.Model):
def vals(self):
return self.annotations.vals

@vals.setter
def vals(self, vals):
AnnotationType = swapper.load_model('annotate', 'AnnotationType')
types, success = AnnotationType.objects.resolve_names(*(vals.keys()))
if not success:
raise TypeError("Could not identify one or more annotation types!")

for name, atype in types.items():
annot, is_new = self.annotations.get_or_create(type=atype)
annot.value = vals[name]
annot.save()

class Meta:
abstract = True

Expand Down

0 comments on commit 9029fdf

Please sign in to comment.