class Plate(StandardModel): STATUSES = utils.self_zip(constants.STANDARD_STATUSES) status = models.CharField(max_length=255, choices=STATUSES) TYPES = utils.self_zip(constants.PLATE_TYPES) type = models.CharField(max_length=255, choices=TYPES) replicate = models.CharField(max_length=255) owner = models.ForeignKey(User, related_name='plate_owner', null=True, blank=True) DIMENSIONS = utils.self_zip(constants.PLATE_DIMENSIONS) dimension = models.CharField(max_length=255, choices=DIMENSIONS, null=True, blank=True) class Meta: app_label = "core" db_table = 'plate' unique_together = ("name", "replicate") ordering = ['-date_created'] def full_name(self): return "{0}_{1}".format(self.name, self.replicate) def __str__(self): return "{0}_{1}".format(self.name, self.replicate) def get_absolute_url(self): return reverse('plate-detail', kwargs={'pk': self.pk})
class Project(StandardModel): TYPES = utils.self_zip(constants.PROJECT_TYPES) STATUSES = utils.self_zip(constants.PROJECT_STATUSES) owner = models.ForeignKey(User, related_name='project_owner') type = models.CharField(max_length=255, choices=TYPES) status = models.CharField(max_length=255, choices=STATUSES, default=constants.STATUS_ACTIVE) class Meta: app_label = "core" db_table = 'project' def __str__(self): return self.name def get_absolute_url(self): return reverse('projects-detail', kwargs={'pk': self.pk})
class ContextGene(Base): CONTEXTS = utils.self_zip(constants.GENE_CONTEXTS) gene = models.ForeignKey(Gene) context = models.CharField(max_length=255, choices=CONTEXTS) class Meta: app_label = "core" db_table = 'context_gene' ordering = ['-date_created'] unique_together = ('gene', 'context') def __str__(self): return "{0} {1}".format(self.gene.name, self.context)
class Printer(StandardModel): TYPES = utils.self_zip(constants.ALL_PRINTER_TYPES) type = models.CharField(max_length=255,choices=TYPES) address = models.CharField(max_length=255,null=True,blank=True) location = models.ForeignKey(Location,null=True,blank=True) label_formats = models.ManyToManyField(LabelFormat,blank=True,through='PrinterToLabelFormat') class Meta: app_label = "core" db_table = 'printer' verbose_name_plural = 'printers' def __str__(self): return "{0}({1})".format(self.name,self.address)
class Storage(StandardModel): STATUSES = utils.self_zip(constants.STANDARD_STATUSES) status = models.CharField(max_length=255, choices=STATUSES) location = models.CharField(max_length=255, null=True, blank=True) parent = models.ForeignKey("self", null=True, blank=True) type = models.ForeignKey( StorageType, null=True, blank=True, ) holds_containers = models.BooleanField() holds_samples = models.BooleanField() class Meta: app_label = "core" db_table = 'storage' verbose_name_plural = 'storage' unique_together = ('name', ) def __str__(self): if self.type: return "{0} {1}".format(self.type.name, self.name) else: return "N/A {0}".format(self.name) def get_ancestors(self): logger.debug("getting ancestors") if self.parent is None: return [] return [self.parent] + self.parent.get_ancestors() def get_descendants(self): tree = [] tree = tree + list(self.storage_set.all()) for s in self.storage_set.all(): tree = tree + s.get_descendants() return tree def get_samples(self): tree = [] tree = tree + list(self.sample_set.all()) for s in self.storage_set.all(): tree = tree + s.get_samples() return tree
class ExperimentAttachment(Base): TYPES = utils.self_zip(constants.ATTACHMENT_TYPES) experiment = models.ForeignKey(Experiment) type = models.CharField(max_length=255, choices=TYPES) class Meta: app_label = "core" db_table = 'experiment_attachment' ordering = ['-date_created'] def filename(self): return os.path.basename(self.file.name) def get_upload_path(instance, filename): return os.path.join("{0}/{1}/{2}".format( constants.EXPERIMENT_ATTACHMENTS, instance.experiment.id, filename)) file = models.FileField(upload_to=get_upload_path) def __str__(self): return self.file.url
class ProjectAttachment(Base): TYPES = utils.self_zip(constants.ATTACHMENT_TYPES) project = models.ForeignKey(Project) type = models.CharField(max_length=255, choices=TYPES) file = models.FileField(upload_to='datafiles/%Y/%m/%d') class Meta: app_label = "core" db_table = 'project_attachment' def filename(self): return os.path.basename(self.file.name) def get_upload_path(instance, filename): return os.path.join("{0}/{1}/{2}".format(constants.PROJECT_ATTACHMENTS, instance.project.id, filename)) file = models.FileField(upload_to=get_upload_path) def __str__(self): return self.file.url
class Note(Base): TYPES = utils.self_zip(constants.NOTE_TYPES) note = models.TextField() parent_note = models.ForeignKey('self', null=True, blank=True, related_name="parent") note_type = models.CharField(max_length=255, choices=TYPES) class Meta: app_label = "core" db_table = 'note' content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() content_object = fields.GenericForeignKey('content_type', 'object_id') def __str__(self): return self.note def get_json(self): return json.JSONDecoder().decode( serializers.serialize('json', [self], relations=('created_by')))[0]
class Sample(PolymorphicModel, CaseInsensitiveNamedModel): STATUSES = utils.self_zip(constants.STANDARD_STATUSES) sample_type = models.ForeignKey(SampleType) material = models.ForeignKey(Material) status = models.CharField(max_length=255,choices=STATUSES,default=constants.STATUS_ACTIVE) owner = models.ForeignKey(User,null=True,blank=True) source = models.ForeignKey(Source,null=True,blank=True) lot = models.CharField(max_length=255, null=True, blank=True) volume = models.CharField(max_length=255, null=True, blank=True) concentration = models.CharField(max_length=255, null=True, blank=True) concentration_units = models.CharField(max_length=255, null=True, blank=True) project = models.ManyToManyField(Project,blank=True) storage = models.ForeignKey(Storage,null=True, blank=True) unit_count = models.CharField(max_length=255, null=True, blank=True) notes = fields.GenericRelation(Note) sample_links = models.ManyToManyField( 'self', through='SampleToSample', symmetrical=False, related_name="linked_to", blank=True ) def _has_alert_note(self): logger.debug('looking for alert note') return self.notes.filter(note_type=constants.TYPE_ALERT).exists() has_alert_note = property(_has_alert_note) class Meta: app_label = "core" db_table = 'sample' verbose_name_plural = 'samples' unique_together = ("name",) ordering = ['-date_created'] def save(self, *args, **kwargs): if not self.name: self.name = Sample.name_generator() super(Sample, self).save(*args, **kwargs) def get_absolute_url(self): return reverse('samples-detail', kwargs={'pk': self.pk}) def __str__(self): return self.name def add_sample_link(self, sample, link_type): link, created = SampleToSample.objects.get_or_create( source_sample=self, target_sample=sample, type=link_type ) return link def remove_sample_link(self, sample, link_type): SampleToSample.objects.filter( source_sample=self, target_sample=sample, type=link_type ).delete() return def get_sample_links(self, link_type): return self.sample_links.filter( target_samples__type=link_type, target_samples__source_sample=self ) def get_related_to(self, link_type): return self.linked_to.filter( source_samples__type=link_type, source_samples__target_sample=self ) def get_children(self): logger.debug("in generic get children") link_type = SampleLink.objects.get(name=constants.LINK_TYPE_CHILD) return self.get_sample_links(link_type) def get_parents(self): logger.debug("in generic get parents") link_type = SampleLink.objects.get(name=constants.LINK_TYPE_PARENT) return self.get_related_to(link_type) @classmethod def name_generator(cls): return "S-{0}".format(uuid.uuid4()) # get the next value in the sequence based on the record name # record_1 would generate 2 # record_10 would generate 11 @staticmethod def get_operational_index(value): sql_string = """ select max( to_number( substring(name from char_length(%(value)s) + position(%(value)s in name)), '999' ) + 1 ) from sample where name ~ (%(value)s || '[0-9]+$'); """ index = 1 try: cursor = connection.cursor() cursor.execute(sql_string, {'value': value}) row = cursor.fetchone() logger.debug(row) index = row[0] if index is None: index = 1 except Exception as e: logger.debug(e) logger.debug("exception while looking up values") index = 1 logger.debug("returning the following index {0}".format(index)) return index
class Experiment(PolymorphicModel, StandardModel): TYPES = utils.self_zip(constants.EXPERIMENT_TYPES) STATUSES = utils.self_zip(constants.EXPERIMENT_STATUSES) project = models.ForeignKey(Project) owner = models.ForeignKey(User, related_name='experiment_owner') type = models.CharField(max_length=255, choices=TYPES) status = models.CharField(max_length=255, choices=STATUSES, default=constants.STATUS_ACTIVE) class Meta: app_label = "core" db_table = 'experiment' unique_together = ('name', 'project') ordering = ['-date_created'] def get_experiment_dir(self): utils.create_directory( os.path.join(settings.DATA_ROOT, constants.EXPERIMENT_DATA_FILES, str(self.id))) return os.path.join(settings.DATA_ROOT, constants.EXPERIMENT_DATA_FILES, str(self.id)) def __str__(self): return self.name def get_absolute_url(self): return reverse('experiments-detail', kwargs={'pk': self.pk}) # get the next value in the sequence based on the record name # record_1 would generate 2 # record_10 would generate 11 @staticmethod def get_operational_index(value): replacement_value = "{0}_".format(value) predicate_value = "{0}_[0-9]+$".format(value) sql_string = """ select max( to_number( substring(name from char_length(%(replacement_value)s) + position(%(replacement_value)s in name)), '999' ) + 1 ) from experiment where name ~ (%(predicate_value)s); """ index = 1 try: logger.debug(sql_string) cursor = connection.cursor() cursor.execute( sql_string, { 'replacement_value': replacement_value, 'predicate_value': predicate_value }) row = cursor.fetchone() logger.debug(row) index = row[0] if index is None: index = 1 except Exception as e: logger.debug(e) logger.debug("exception while looking up values") index = 1 logger.debug("returning the following index {0}".format(index)) return index