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=3, null=False)
148 sequence = models.CharField(max_length=12, blank=True, null=True)
151 unique_together = ('adapter_type', 'multiplex_id')
153 class Library(models.Model):
154 id = models.CharField(max_length=10, primary_key=True)
155 library_name = models.CharField(max_length=100, unique=True)
156 library_species = models.ForeignKey(Species)
157 hidden = models.BooleanField()
158 account_number = models.CharField(max_length=100, null=True, blank=True)
159 cell_line = models.ForeignKey(Cellline, blank=True, null=True,
160 verbose_name="Background")
161 condition = models.ForeignKey(Condition, blank=True, null=True)
162 antibody = models.ForeignKey(Antibody,blank=True,null=True)
163 affiliations = models.ManyToManyField(
164 Affiliation,related_name='library_affiliations',null=True)
165 tags = models.ManyToManyField(Tag,related_name='library_tags',
166 blank=True,null=True)
167 REPLICATE_NUM = ((1,1),(2,2),(3,3),(4,4))
168 replicate = models.PositiveSmallIntegerField(choices=REPLICATE_NUM,
169 blank=True,null=True)
170 experiment_type = models.ForeignKey(ExperimentType)
171 library_type = models.ForeignKey(LibraryType, blank=True, null=True,
172 verbose_name="Adapter Type")
173 multiplex_id = models.CharField(max_length=128,
174 blank=True, null=True,
175 verbose_name="Index ID")
176 creation_date = models.DateField(blank=True, null=True)
177 made_for = models.CharField(max_length=50, blank=True,
178 verbose_name='ChIP/DNA/RNA Made By')
179 made_by = models.CharField(max_length=50, blank=True, default="Lorian")
181 PROTOCOL_END_POINTS = (
183 ('Sample', 'Raw sample'),
184 ('Progress', 'In progress'),
185 ('1A', 'Ligation, then gel'),
186 ('PCR', 'Ligation, then PCR'),
187 ('1Ab', 'Ligation, PCR, then gel'),
188 ('1Ac', 'Ligation, gel, then 12x PCR'),
189 ('1Aa', 'Ligation, gel, then 18x PCR'),
190 ('2A', 'Ligation, PCR, gel, PCR'),
191 ('Done', 'Completed'),
193 PROTOCOL_END_POINTS_DICT = dict(PROTOCOL_END_POINTS)
194 stopping_point = models.CharField(max_length=25,
195 choices=PROTOCOL_END_POINTS,
198 amplified_from_sample = models.ForeignKey('self',
199 related_name='amplified_into_sample',
200 blank=True, null=True)
202 undiluted_concentration = models.DecimalField("Concentration",
203 max_digits=5, decimal_places=2, blank=True, null=True,
204 help_text=u"Undiluted concentration (ng/\u00b5l)")
205 # note \u00b5 is the micro symbol in unicode
206 successful_pM = models.DecimalField(max_digits=9,
207 decimal_places=1, blank=True, null=True)
208 ten_nM_dilution = models.BooleanField()
209 gel_cut_size = models.IntegerField(default=225, blank=True, null=True)
210 insert_size = models.IntegerField(blank=True, null=True)
211 notes = models.TextField(blank=True)
213 bioanalyzer_summary = models.TextField(blank=True,default="")
214 bioanalyzer_concentration = models.DecimalField(max_digits=5,
215 decimal_places=2, blank=True, null=True,
216 help_text=u"(ng/\u00b5l)")
217 bioanalyzer_image_url = models.URLField(blank=True,default="")
219 def __unicode__(self):
220 return u'#%s: %s' % (self.id, self.library_name)
223 verbose_name_plural = "libraries"
224 #ordering = ["-creation_date"]
227 def antibody_name(self):
228 str ='<a target=_self href="/admin/samples/antibody/'+self.antibody.id.__str__()+'/" title="'+self.antibody.__str__()+'">'+self.antibody.label+'</a>'
230 antibody_name.allow_tags = True
233 return self.library_species.common_name
235 def index_sequences(self):
236 """Return a dictionary of multiplex index id to sequence
237 Return None if the library can't multiplex,
240 if self.library_type is None:
242 if not self.library_type.can_multiplex:
244 if self.multiplex_id is None or len(self.multiplex_id) == 0:
245 return 'Err: id empty'
247 multiplex_ids = self.multiplex_id.split(',')
248 for multiplex_id in multiplex_ids:
250 multiplex = MultiplexIndex.objects.get(
251 adapter_type = self.library_type.id,
252 multiplex_id = multiplex_id)
253 sequences[multiplex_id] = multiplex.sequence
254 except MultiplexIndex.DoesNotExist, e:
255 sequences[multiplex_id] = 'Err: index not found'
258 def index_sequence_text(self, seperator=' '):
259 """Return formatted multiplex index sequences"""
260 sequences = self.index_sequences()
261 multiplex_ids = sequences.keys()
263 return seperator.join(( "%s:%s" %(i,sequences[i]) for i in multiplex_ids))
264 index_sequence_text.short_description = "Index"
267 def affiliation(self):
268 affs = self.affiliations.all().order_by('name')
272 ar.append(t.__unicode__())
273 return '%s' % (", ".join(ar))
275 def is_archived(self):
277 returns True if archived else False
279 if self.longtermstorage_set.count() > 0:
284 def stopping_point_name(self):
285 end_points = Library.PROTOCOL_END_POINTS_DICT
286 name = end_points.get(self.stopping_point, None)
288 name = "Lookup Error"
289 logger.error("protocol stopping point in database didn't match names in library model")
294 affs = self.tags.all().order_by('tag_name')
297 ar.append(t.__unicode__())
298 return u'%s' % ( ", ".join(ar))
301 str ='<a target=_self href="/admin/experiments/datarun/?q='+self.id+'" title="Check All Data Runs for This Specific Library ..." ">Data Run</a>'
303 DataRun.allow_tags = True
305 def aligned_m_reads(self):
306 return getLibReads(self.id)
308 def aligned_reads(self):
309 res = getLibReads(self.id)
313 return u'<div style="border:solid red 2px">'+res[2]+'</div>'
315 rc = "%1.2f" % (res[1]/1000000.0)
316 # 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
318 bgcolor = '#ff3300' # Red
319 rc_thr = [10000000,5000000,3000000]
320 if self.experiment_type == 'RNA-seq':
321 rc_thr = [20000000,10000000,6000000]
323 if res[1] > rc_thr[0]:
324 bgcolor = '#66ff66' # Green
326 if res[1] > rc_thr[1]:
327 bgcolor ='#00ccff' # Blue
329 if res[1] > rc_thr[2]:
330 bgcolor ='#ffcc33' # Orange
331 tstr = '<div style="background-color:'+bgcolor+';color:black">'
332 tstr += res[0].__unicode__()+' Lanes, '+rc+' M Reads'
334 else: tstr = 'not processed yet'
336 aligned_reads.allow_tags = True
340 summary_url = self.get_absolute_url()
341 return '<a href="%s">S</a>' % (summary_url,)
342 public.allow_tags = True
345 def get_absolute_url(self):
346 return ('htsworkflow.frontend.samples.views.library_to_flowcells', [str(self.id)])
348 def get_admin_url(self):
349 return urlresolvers.reverse('admin:samples_library_change',
354 Provide some site-specific customization for the django user class
356 #objects = UserManager()
359 ordering = ['first_name', 'last_name', 'username']
362 return '/admin/%s/%s/%d' % (self._meta.app_label, self._meta.module_name, self.id)
364 def __unicode__(self):
365 #return unicode(self.username) + u" (" + unicode(self.get_full_name()) + u")"
366 return unicode(self.get_full_name()) + u' (' + unicode(self.username) + ')'
368 def HTSUserInsertID(sender, instance, **kwargs):
370 Force addition of HTSUsers when someone just modifies the auth_user object
372 u = HTSUser.objects.filter(pk=instance.id)
374 cursor = connection.cursor()
375 cursor.execute('INSERT INTO samples_htsuser (user_ptr_id) VALUES (%s);' % (instance.id,))
378 post_save.connect(HTSUserInsertID, sender=User)