3 from django.db import models
4 from django.contrib.auth.models import User, UserManager
5 from django.core import urlresolvers
6 from django.db.models.signals import pre_save, post_save
7 from django.db import connection
8 from htsworkflow.frontend.reports.libinfopar import *
10 logger = logging.getLogger(__name__)
12 class Antibody(models.Model):
13 antigene = models.CharField(max_length=500, db_index=True)
16 # alter table fctracker_antibody add column "nickname" varchar(20) NULL;
17 nickname = models.CharField(
23 catalog = models.CharField(max_length=50, blank=True, null=True)
24 antibodies = models.CharField(max_length=500, db_index=True)
25 source = models.CharField(max_length=500, blank=True, null=True, db_index=True)
26 biology = models.TextField(blank=True, null=True)
27 notes = models.TextField(blank=True, null=True)
28 def __unicode__(self):
29 return u'%s - %s' % (self.antigene, self.antibodies)
31 verbose_name_plural = "antibodies"
32 ordering = ["antigene"]
34 class Cellline(models.Model):
35 cellline_name = models.CharField(max_length=100, unique=True, db_index=True)
36 nickname = models.CharField(max_length=20,
41 notes = models.TextField(blank=True)
42 def __unicode__(self):
43 return unicode(self.cellline_name)
46 ordering = ["cellline_name"]
48 class Condition(models.Model):
49 condition_name = models.CharField(
50 max_length=2000, unique=True, db_index=True)
51 nickname = models.CharField(max_length=20,
55 verbose_name = 'Short Name')
56 notes = models.TextField(blank=True)
58 def __unicode__(self):
59 return unicode(self.condition_name)
62 ordering = ["condition_name"]
65 class ExperimentType(models.Model):
66 name = models.CharField(max_length=50, unique=True)
68 def __unicode__(self):
69 return unicode(self.name)
71 class Tag(models.Model):
72 tag_name = models.CharField(max_length=100, db_index=True,blank=False,null=False)
74 #('Antibody','Antibody'),
75 #('Cellline', 'Cellline'),
76 #('Condition', 'Condition'),
77 ('Library', 'Library'),
80 context = models.CharField(max_length=50,
81 choices=TAG_CONTEXT, default='Library')
83 def __unicode__(self):
84 return u'%s' % (self.tag_name)
87 ordering = ["context","tag_name"]
89 class Species(models.Model):
90 scientific_name = models.CharField(max_length=256,
94 common_name = models.CharField(max_length=256, blank=True)
95 #use_genome_build = models.CharField(max_length=100, blank=False, null=False)
97 def __unicode__(self):
98 return u'%s (%s)' % (self.scientific_name, self.common_name)
101 verbose_name_plural = "species"
102 ordering = ["scientific_name"]
105 def get_absolute_url(self):
106 return ('htsworkflow.frontend.samples.views.species', [str(self.id)])
108 class Affiliation(models.Model):
109 name = models.CharField(max_length=256, db_index=True, verbose_name='Name')
110 contact = models.CharField(max_length=256, null=True, blank=True,verbose_name='Lab Name')
111 email = models.EmailField(null=True,blank=True)
112 users = models.ManyToManyField('HTSUser', null=True, blank=True)
113 users.admin_order_field = "username"
115 def __unicode__(self):
116 str = unicode(self.name)
117 if self.contact is not None and len(self.contact) > 0:
118 str += u' ('+self.contact+u')'
122 users = self.users.all().order_by('username')
123 return ", ".join([unicode(a) for a in users ])
126 ordering = ["name","contact"]
127 unique_together = (("name", "contact"),)
129 class LibraryType(models.Model):
130 name = models.CharField(max_length=255, unique=True,
132 is_paired_end = models.BooleanField(default=True,
133 help_text="can you do a paired end run with this adapter")
134 can_multiplex = models.BooleanField(default=True,
135 help_text="Does this adapter provide multiplexing?")
137 def __unicode__(self):
138 return unicode(self.name)
144 class MultiplexIndex(models.Model):
145 """Map adapter types to the multiplex sequence"""
146 adapter_type = models.ForeignKey(LibraryType)
147 multiplex_id = models.CharField(max_length=6, null=False)
148 sequence = models.CharField(max_length=12, blank=True, null=True)
151 verbose_name_plural = "multiplex indicies"
152 unique_together = ('adapter_type', 'multiplex_id')
154 class Library(models.Model):
155 id = models.CharField(max_length=10, primary_key=True)
156 library_name = models.CharField(max_length=100, unique=True)
157 library_species = models.ForeignKey(Species)
158 hidden = models.BooleanField()
159 account_number = models.CharField(max_length=100, null=True, blank=True)
160 cell_line = models.ForeignKey(Cellline, blank=True, null=True,
161 verbose_name="Background")
162 condition = models.ForeignKey(Condition, blank=True, null=True)
163 antibody = models.ForeignKey(Antibody,blank=True,null=True)
164 affiliations = models.ManyToManyField(
165 Affiliation,related_name='library_affiliations',null=True)
166 tags = models.ManyToManyField(Tag,related_name='library_tags',
167 blank=True,null=True)
168 REPLICATE_NUM = [(x,x) for x in range(1,7)]
169 replicate = models.PositiveSmallIntegerField(choices=REPLICATE_NUM,
170 blank=True,null=True)
171 experiment_type = models.ForeignKey(ExperimentType)
172 library_type = models.ForeignKey(LibraryType, blank=True, null=True,
173 verbose_name="Adapter Type")
174 multiplex_id = models.CharField(max_length=128,
175 blank=True, null=True,
176 verbose_name="Index ID")
177 creation_date = models.DateField(blank=True, null=True)
178 made_for = models.CharField(max_length=50, blank=True,
179 verbose_name='ChIP/DNA/RNA Made By')
180 made_by = models.CharField(max_length=50, blank=True, default="Lorian")
182 PROTOCOL_END_POINTS = (
184 ('Sample', 'Raw sample'),
185 ('Progress', 'In progress'),
186 ('1A', 'Ligation, then gel'),
187 ('PCR', 'Ligation, then PCR'),
188 ('1Ab', 'Ligation, PCR, then gel'),
189 ('1Ac', 'Ligation, gel, then 12x PCR'),
190 ('1Aa', 'Ligation, gel, then 18x PCR'),
191 ('2A', 'Ligation, PCR, gel, PCR'),
192 ('Done', 'Completed'),
194 PROTOCOL_END_POINTS_DICT = dict(PROTOCOL_END_POINTS)
195 stopping_point = models.CharField(max_length=25,
196 choices=PROTOCOL_END_POINTS,
199 amplified_from_sample = models.ForeignKey('self',
200 related_name='amplified_into_sample',
201 blank=True, null=True)
203 undiluted_concentration = models.DecimalField("Concentration",
204 max_digits=5, decimal_places=2, blank=True, null=True,
205 help_text=u"Undiluted concentration (ng/\u00b5l)")
206 # note \u00b5 is the micro symbol in unicode
207 successful_pM = models.DecimalField(max_digits=9,
208 decimal_places=1, blank=True, null=True)
209 ten_nM_dilution = models.BooleanField()
210 gel_cut_size = models.IntegerField(default=225, blank=True, null=True)
211 insert_size = models.IntegerField(blank=True, null=True)
212 notes = models.TextField(blank=True)
214 bioanalyzer_summary = models.TextField(blank=True,default="")
215 bioanalyzer_concentration = models.DecimalField(max_digits=5,
216 decimal_places=2, blank=True, null=True,
217 help_text=u"(ng/\u00b5l)")
218 bioanalyzer_image_url = models.URLField(blank=True,default="")
220 def __unicode__(self):
221 return u'#%s: %s' % (self.id, self.library_name)
224 verbose_name_plural = "libraries"
225 #ordering = ["-creation_date"]
228 def antibody_name(self):
229 str ='<a target=_self href="/admin/samples/antibody/'+self.antibody.id.__str__()+'/" title="'+self.antibody.__str__()+'">'+self.antibody.label+'</a>'
231 antibody_name.allow_tags = True
234 return self.library_species.common_name
236 def index_sequences(self):
237 """Return a dictionary of multiplex index id to sequence
238 Return None if the library can't multiplex,
241 if self.library_type is None:
243 if not self.library_type.can_multiplex:
245 if self.multiplex_id is None or len(self.multiplex_id) == 0:
246 return 'Err: id empty'
248 multiplex_expressions = self.multiplex_id.split(',')
249 for multiplex_term in multiplex_expressions:
250 pairs = multiplex_term.split('-')
253 seq = self._lookup_index(pairs[0])
254 elif len(pairs) == 2:
255 key = pairs[0] + '-' + pairs[1]
256 seq0 = self._lookup_index(pairs[0])
257 seq1 = self._lookup_index(pairs[1])
258 if seq0 is None or seq1 is None:
261 seq = seq0 + '-' + seq1
263 raise RuntimeError("Too many - seperated sequences")
265 seq = 'Err: index not found'
269 def _lookup_index(self, multiplex_id):
271 multiplex = MultiplexIndex.objects.get(
272 adapter_type = self.library_type.id,
273 multiplex_id = multiplex_id)
274 return multiplex.sequence
275 except MultiplexIndex.DoesNotExist, e:
278 def index_sequence_text(self, seperator=' '):
279 """Return formatted multiplex index sequences"""
280 sequences = self.index_sequences()
281 if sequences is None:
283 multiplex_ids = sequences.keys()
285 return seperator.join(( "%s:%s" %(i,sequences[i]) for i in multiplex_ids))
286 index_sequence_text.short_description = "Index"
289 def affiliation(self):
290 affs = self.affiliations.all().order_by('name')
294 ar.append(t.__unicode__())
295 return '%s' % (", ".join(ar))
297 def is_archived(self):
299 returns True if archived else False
301 if self.longtermstorage_set.count() > 0:
306 def stopping_point_name(self):
307 end_points = Library.PROTOCOL_END_POINTS_DICT
308 name = end_points.get(self.stopping_point, None)
310 name = "Lookup Error"
311 logger.error("protocol stopping point in database didn't match names in library model")
316 affs = self.tags.all().order_by('tag_name')
319 ar.append(t.__unicode__())
320 return u'%s' % ( ", ".join(ar))
323 str ='<a target=_self href="/admin/experiments/datarun/?q='+self.id+'" title="Check All Data Runs for This Specific Library ..." ">Data Run</a>'
325 DataRun.allow_tags = True
327 def aligned_m_reads(self):
328 return getLibReads(self.id)
330 def aligned_reads(self):
331 res = getLibReads(self.id)
335 return u'<div style="border:solid red 2px">'+res[2]+'</div>'
337 rc = "%1.2f" % (res[1]/1000000.0)
338 # 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
340 bgcolor = '#ff3300' # Red
341 rc_thr = [10000000,5000000,3000000]
342 if self.experiment_type == 'RNA-seq':
343 rc_thr = [20000000,10000000,6000000]
345 if res[1] > rc_thr[0]:
346 bgcolor = '#66ff66' # Green
348 if res[1] > rc_thr[1]:
349 bgcolor ='#00ccff' # Blue
351 if res[1] > rc_thr[2]:
352 bgcolor ='#ffcc33' # Orange
353 tstr = '<div style="background-color:'+bgcolor+';color:black">'
354 tstr += res[0].__unicode__()+' Lanes, '+rc+' M Reads'
356 else: tstr = 'not processed yet'
358 aligned_reads.allow_tags = True
362 summary_url = self.get_absolute_url()
363 return '<a href="%s">S</a>' % (summary_url,)
364 public.allow_tags = True
367 def get_absolute_url(self):
368 return ('htsworkflow.frontend.samples.views.library_to_flowcells', [str(self.id)])
370 def get_admin_url(self):
371 return urlresolvers.reverse('admin:samples_library_change',
376 Provide some site-specific customization for the django user class
378 #objects = UserManager()
381 ordering = ['first_name', 'last_name', 'username']
384 return '/admin/%s/%s/%d' % (self._meta.app_label, self._meta.module_name, self.id)
386 def __unicode__(self):
387 #return unicode(self.username) + u" (" + unicode(self.get_full_name()) + u")"
388 return unicode(self.get_full_name()) + u' (' + unicode(self.username) + ')'
390 def HTSUserInsertID(sender, instance, **kwargs):
392 Force addition of HTSUsers when someone just modifies the auth_user object
394 u = HTSUser.objects.filter(pk=instance.id)
396 cursor = connection.cursor()
397 cursor.execute('INSERT INTO samples_htsuser (user_ptr_id) VALUES (%s);' % (instance.id,))
400 post_save.connect(HTSUserInsertID, sender=User)