4 from django.db import models
5 from django.contrib.auth.models import User, UserManager
6 from django.core import urlresolvers
7 from django.db.models.signals import pre_save, post_save
8 from django.db import connection
9 from htsworkflow.frontend.reports.libinfopar import *
11 logger = logging.getLogger(__name__)
13 class Antibody(models.Model):
14 antigene = models.CharField(max_length=500, db_index=True)
17 # alter table fctracker_antibody add column "nickname" varchar(20) NULL;
18 nickname = models.CharField(
24 catalog = models.CharField(max_length=50, blank=True, null=True)
25 antibodies = models.CharField(max_length=500, db_index=True)
26 source = models.CharField(max_length=500, blank=True, null=True, db_index=True)
27 biology = models.TextField(blank=True, null=True)
28 notes = models.TextField(blank=True, null=True)
29 def __unicode__(self):
30 return u'%s - %s' % (self.antigene, self.antibodies)
32 verbose_name_plural = "antibodies"
33 ordering = ["antigene"]
35 class Cellline(models.Model):
36 cellline_name = models.CharField(max_length=100, unique=True, db_index=True)
37 nickname = models.CharField(max_length=20,
42 notes = models.TextField(blank=True)
43 def __unicode__(self):
44 return unicode(self.cellline_name)
47 ordering = ["cellline_name"]
49 class Condition(models.Model):
50 condition_name = models.CharField(
51 max_length=2000, unique=True, db_index=True)
52 nickname = models.CharField(max_length=20,
56 verbose_name = 'Short Name')
57 notes = models.TextField(blank=True)
59 def __unicode__(self):
60 return unicode(self.condition_name)
63 ordering = ["condition_name"]
66 class ExperimentType(models.Model):
67 name = models.CharField(max_length=50, unique=True)
69 def __unicode__(self):
70 return unicode(self.name)
72 class Tag(models.Model):
73 tag_name = models.CharField(max_length=100, db_index=True,blank=False,null=False)
75 #('Antibody','Antibody'),
76 #('Cellline', 'Cellline'),
77 #('Condition', 'Condition'),
78 ('Library', 'Library'),
81 context = models.CharField(max_length=50,
82 choices=TAG_CONTEXT, default='Library')
84 def __unicode__(self):
85 return u'%s' % (self.tag_name)
88 ordering = ["context","tag_name"]
90 class Species(models.Model):
91 scientific_name = models.CharField(max_length=256,
95 common_name = models.CharField(max_length=256, blank=True)
96 #use_genome_build = models.CharField(max_length=100, blank=False, null=False)
98 def __unicode__(self):
99 return u'%s (%s)' % (self.scientific_name, self.common_name)
102 verbose_name_plural = "species"
103 ordering = ["scientific_name"]
106 def get_absolute_url(self):
107 return ('htsworkflow.frontend.samples.views.species', [str(self.id)])
109 class Affiliation(models.Model):
110 name = models.CharField(max_length=256, db_index=True, verbose_name='Name')
111 contact = models.CharField(max_length=256, null=True, blank=True,verbose_name='Lab Name')
112 email = models.EmailField(null=True,blank=True)
113 users = models.ManyToManyField('HTSUser', null=True, blank=True)
114 users.admin_order_field = "username"
116 def __unicode__(self):
117 str = unicode(self.name)
118 if self.contact is not None and len(self.contact) > 0:
119 str += u' ('+self.contact+u')'
123 users = self.users.all().order_by('username')
124 return ", ".join([unicode(a) for a in users ])
127 ordering = ["name","contact"]
128 unique_together = (("name", "contact"),)
130 class LibraryType(models.Model):
131 name = models.CharField(max_length=255, unique=True,
133 is_paired_end = models.BooleanField(default=True,
134 help_text="can you do a paired end run with this adapter")
135 can_multiplex = models.BooleanField(default=True,
136 help_text="Does this adapter provide multiplexing?")
138 def __unicode__(self):
139 return unicode(self.name)
145 class MultiplexIndex(models.Model):
146 """Map adapter types to the multiplex sequence"""
147 adapter_type = models.ForeignKey(LibraryType)
148 multiplex_id = models.CharField(max_length=6, null=False)
149 sequence = models.CharField(max_length=12, blank=True, null=True)
152 verbose_name_plural = "multiplex indicies"
153 unique_together = ('adapter_type', 'multiplex_id')
155 class Library(models.Model):
156 id = models.CharField(max_length=10, primary_key=True)
157 library_name = models.CharField(max_length=100, unique=True)
158 library_species = models.ForeignKey(Species)
159 hidden = models.BooleanField()
160 account_number = models.CharField(max_length=100, null=True, blank=True)
161 cell_line = models.ForeignKey(Cellline, blank=True, null=True,
162 verbose_name="Background")
163 condition = models.ForeignKey(Condition, blank=True, null=True)
164 antibody = models.ForeignKey(Antibody,blank=True,null=True)
165 affiliations = models.ManyToManyField(
166 Affiliation,related_name='library_affiliations',null=True)
167 tags = models.ManyToManyField(Tag,related_name='library_tags',
168 blank=True,null=True)
169 REPLICATE_NUM = [(x,x) for x in range(1,7)]
170 replicate = models.PositiveSmallIntegerField(choices=REPLICATE_NUM,
171 blank=True,null=True)
172 experiment_type = models.ForeignKey(ExperimentType)
173 library_type = models.ForeignKey(LibraryType, blank=True, null=True,
174 verbose_name="Adapter Type")
175 multiplex_id = models.CharField(max_length=128,
176 blank=True, null=True,
177 verbose_name="Index ID")
178 creation_date = models.DateField(blank=True, null=True)
179 made_for = models.CharField(max_length=50, blank=True,
180 verbose_name='ChIP/DNA/RNA Made By')
181 made_by = models.CharField(max_length=50, blank=True, default="Lorian")
183 PROTOCOL_END_POINTS = (
185 ('Sample', 'Raw sample'),
186 ('Progress', 'In progress'),
187 ('1A', 'Ligation, then gel'),
188 ('PCR', 'Ligation, then PCR'),
189 ('1Ab', 'Ligation, PCR, then gel'),
190 ('1Ac', 'Ligation, gel, then 12x PCR'),
191 ('1Aa', 'Ligation, gel, then 18x PCR'),
192 ('2A', 'Ligation, PCR, gel, PCR'),
193 ('Done', 'Completed'),
195 PROTOCOL_END_POINTS_DICT = dict(PROTOCOL_END_POINTS)
196 stopping_point = models.CharField(max_length=25,
197 choices=PROTOCOL_END_POINTS,
200 amplified_from_sample = models.ForeignKey('self',
201 related_name='amplified_into_sample',
202 blank=True, null=True)
204 undiluted_concentration = models.DecimalField("Concentration",
205 max_digits=5, decimal_places=2, blank=True, null=True,
206 help_text=u"Undiluted concentration (ng/\u00b5l)")
207 # note \u00b5 is the micro symbol in unicode
208 successful_pM = models.DecimalField(max_digits=9,
209 decimal_places=1, blank=True, null=True)
210 ten_nM_dilution = models.BooleanField()
211 gel_cut_size = models.IntegerField(default=225, blank=True, null=True)
212 insert_size = models.IntegerField(blank=True, null=True)
213 notes = models.TextField(blank=True)
215 bioanalyzer_summary = models.TextField(blank=True,default="")
216 bioanalyzer_concentration = models.DecimalField(max_digits=5,
217 decimal_places=2, blank=True, null=True,
218 help_text=u"(ng/\u00b5l)")
219 bioanalyzer_image_url = models.URLField(blank=True,default="")
221 def __unicode__(self):
222 return u'#%s: %s' % (self.id, self.library_name)
225 verbose_name_plural = "libraries"
226 #ordering = ["-creation_date"]
229 def antibody_name(self):
230 str ='<a target=_self href="/admin/samples/antibody/'+self.antibody.id.__str__()+'/" title="'+self.antibody.__str__()+'">'+self.antibody.label+'</a>'
232 antibody_name.allow_tags = True
235 return self.library_species.common_name
237 def index_sequences(self):
238 """Return a dictionary of multiplex index id to sequence
239 Return None if the library can't multiplex,
242 if self.library_type is None:
244 if not self.library_type.can_multiplex:
246 if self.multiplex_id is None or len(self.multiplex_id) == 0:
247 return 'Err: id empty'
249 multiplex_expressions = self.multiplex_id.split(',')
250 for multiplex_term in multiplex_expressions:
251 pairs = multiplex_term.split('-')
254 seq = self._lookup_index(pairs[0])
255 elif len(pairs) == 2:
256 key = pairs[0] + '-' + pairs[1]
257 seq0 = self._lookup_index(pairs[0])
258 seq1 = self._lookup_index(pairs[1])
259 if seq0 is None or seq1 is None:
262 seq = seq0 + '-' + seq1
264 raise RuntimeError("Too many - seperated sequences")
266 seq = 'Err: index not found'
270 def _lookup_index(self, multiplex_id):
272 multiplex = MultiplexIndex.objects.get(
273 adapter_type = self.library_type.id,
274 multiplex_id = multiplex_id)
275 return multiplex.sequence
276 except MultiplexIndex.DoesNotExist, e:
279 def index_sequence_text(self, seperator=' '):
280 """Return formatted multiplex index sequences"""
281 sequences = self.index_sequences()
282 if sequences is None:
284 if type(sequences) in types.StringTypes:
286 multiplex_ids = sequences.keys()
288 return seperator.join(( "%s:%s" %(i,sequences[i]) for i in multiplex_ids))
289 index_sequence_text.short_description = "Index"
292 def affiliation(self):
293 affs = self.affiliations.all().order_by('name')
297 ar.append(t.__unicode__())
298 return '%s' % (", ".join(ar))
300 def is_archived(self):
302 returns True if archived else False
304 if self.longtermstorage_set.count() > 0:
309 def stopping_point_name(self):
310 end_points = Library.PROTOCOL_END_POINTS_DICT
311 name = end_points.get(self.stopping_point, None)
313 name = "Lookup Error"
314 logger.error("protocol stopping point in database didn't match names in library model")
319 affs = self.tags.all().order_by('tag_name')
322 ar.append(t.__unicode__())
323 return u'%s' % ( ", ".join(ar))
326 str ='<a target=_self href="/admin/experiments/datarun/?q='+self.id+'" title="Check All Data Runs for This Specific Library ..." ">Data Run</a>'
328 DataRun.allow_tags = True
330 def aligned_m_reads(self):
331 return getLibReads(self.id)
333 def aligned_reads(self):
334 res = getLibReads(self.id)
338 return u'<div style="border:solid red 2px">'+res[2]+'</div>'
340 rc = "%1.2f" % (res[1]/1000000.0)
341 # Color Scheme: green is more than 10M, blue is more than 5M, orange is more than 3M and red is less. For RNAseq, all those thresholds should be doubled
343 bgcolor = '#ff3300' # Red
344 rc_thr = [10000000,5000000,3000000]
345 if self.experiment_type == 'RNA-seq':
346 rc_thr = [20000000,10000000,6000000]
348 if res[1] > rc_thr[0]:
349 bgcolor = '#66ff66' # Green
351 if res[1] > rc_thr[1]:
352 bgcolor ='#00ccff' # Blue
354 if res[1] > rc_thr[2]:
355 bgcolor ='#ffcc33' # Orange
356 tstr = '<div style="background-color:'+bgcolor+';color:black">'
357 tstr += res[0].__unicode__()+' Lanes, '+rc+' M Reads'
359 else: tstr = 'not processed yet'
361 aligned_reads.allow_tags = True
365 summary_url = self.get_absolute_url()
366 return '<a href="%s">S</a>' % (summary_url,)
367 public.allow_tags = True
370 def get_absolute_url(self):
371 return ('htsworkflow.frontend.samples.views.library_to_flowcells', [str(self.id)])
373 def get_admin_url(self):
374 return urlresolvers.reverse('admin:samples_library_change',
379 Provide some site-specific customization for the django user class
381 #objects = UserManager()
384 ordering = ['first_name', 'last_name', 'username']
387 return '/admin/%s/%s/%d' % (self._meta.app_label, self._meta.module_name, self.id)
389 def __unicode__(self):
390 #return unicode(self.username) + u" (" + unicode(self.get_full_name()) + u")"
391 return unicode(self.get_full_name()) + u' (' + unicode(self.username) + ')'
393 def HTSUserInsertID(sender, instance, **kwargs):
395 Force addition of HTSUsers when someone just modifies the auth_user object
397 u = HTSUser.objects.filter(pk=instance.id)
399 cursor = connection.cursor()
400 cursor.execute('INSERT INTO samples_htsuser (user_ptr_id) VALUES (%s);' % (instance.id,))
403 post_save.connect(HTSUserInsertID, sender=User)