Add in 12x / 18x PCR protocol end points from Lorian
[htsworkflow.git] / htsworkflow / frontend / samples / models.py
1 import urlparse
2 from django.db import models
3 from django.contrib.auth.models import User, UserManager
4 from django.db.models.signals import pre_save, post_save
5 from django.db import connection
6 from htsworkflow.frontend import settings
7 from htsworkflow.frontend.reports.libinfopar import *
8
9 # Create your models here.
10
11 class Antibody(models.Model):
12     antigene = models.CharField(max_length=500, db_index=True)
13     # New field Aug/20/08
14     # SQL to add column: 
15     # alter table fctracker_antibody add column "nickname" varchar(20) NULL;
16     nickname = models.CharField(
17         max_length=20,
18         blank=True,
19         null=True, 
20         db_index=True,
21         verbose_name = 'Short Name'
22     )
23     catalog = models.CharField(max_length=50, unique=True, db_index=True)
24     antibodies = models.CharField(max_length=500, db_index=True)
25     source = models.CharField(max_length=500, blank=True, db_index=True)
26     biology = models.TextField(blank=True)
27     notes = models.TextField(blank=True)
28     def __unicode__(self):
29         return u'%s - %s (%s)' % (self.antigene, self.antibodies, self.catalog)
30     class Meta:
31         verbose_name_plural = "antibodies"
32         ordering = ["antigene"]
33
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,
37         blank=True,
38         null=True, 
39         db_index=True,
40         verbose_name = 'Short Name')
41     notes = models.TextField(blank=True)
42     def __unicode__(self):
43         return unicode(self.cellline_name)
44
45     class Meta:
46         ordering = ["cellline_name"]
47
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,
52         blank=True,
53         null=True, 
54         db_index=True,
55         verbose_name = 'Short Name')
56     notes = models.TextField(blank=True)
57
58     def __unicode__(self):
59         return unicode(self.condition_name)
60
61     class Meta:
62         ordering = ["condition_name"]
63
64 class ExperimentType(models.Model):
65   name = models.CharField(max_length=50, unique=True)
66
67   def __unicode__(self):
68     return unicode(self.name)
69
70 class Tag(models.Model): 
71   tag_name = models.CharField(max_length=100, db_index=True,blank=False,null=False) 
72   TAG_CONTEXT = ( 
73       #('Antibody','Antibody'), 
74       #('Cellline', 'Cellline'), 
75       #('Condition', 'Condition'), 
76       ('Library', 'Library'), 
77       ('ANY','ANY'), 
78   ) 
79   context = models.CharField(max_length=50, 
80       choices=TAG_CONTEXT, default='Library') 
81  
82   def __unicode__(self): 
83     return u'%s' % (self.tag_name) 
84  
85   class Meta: 
86     ordering = ["context","tag_name"] 
87  
88 class Species(models.Model):
89   scientific_name = models.CharField(max_length=256, 
90       unique=False, 
91       db_index=True
92   )
93   common_name = models.CharField(max_length=256, blank=True)
94   #use_genome_build = models.CharField(max_length=100, blank=False, null=False)
95
96   def __unicode__(self):
97     return u'%s (%s)' % (self.scientific_name, self.common_name)
98   
99   class Meta:
100     verbose_name_plural = "species"
101     ordering = ["scientific_name"]
102   
103 class Affiliation(models.Model):
104   name = models.CharField(max_length=256, db_index=True, verbose_name='Name')
105   contact = models.CharField(max_length=256, null=True, blank=True,verbose_name='Lab Name')  
106   email = models.EmailField(null=True,blank=True)
107   users = models.ManyToManyField('HTSUser', null=True, blank=True)
108   users.admin_order_field = "username"
109   
110   def __unicode__(self):
111     str = unicode(self.name)
112     if self.contact is not None and len(self.contact) > 0:
113       str += u' ('+self.contact+u')' 
114     return str
115
116   def Users(self):
117       users = self.users.all().order_by('username')
118       return ", ".join([unicode(a) for a in users ])
119
120   class Meta:
121     ordering = ["name","contact"]
122     unique_together = (("name", "contact"),)
123
124 class LibraryType(models.Model):
125   name = models.CharField(max_length=255, unique=True)
126
127   def __unicode__(self):
128     return unicode(self.name)
129
130
131 class Library(models.Model):
132   id = models.CharField(max_length=10, primary_key=True)
133   library_name = models.CharField(max_length=100, unique=True)
134   library_species = models.ForeignKey(Species)
135   # new field 2008 Mar 5, alter table samples_library add column "hidden" NOT NULL default 0;
136   hidden = models.BooleanField()
137   # new field 2009 Oct 6, alter table samples_library add column "account_number" varchar(100) NULL
138   account_number = models.CharField(max_length=100, null=True, blank=True)
139   cell_line = models.ForeignKey(Cellline, blank=True, null=True, verbose_name="Background")
140   condition = models.ForeignKey(Condition, blank=True, null=True)
141   antibody = models.ForeignKey(Antibody,blank=True,null=True)
142   # New field Aug/25/08. SQL: alter table fctracker_library add column "lib_affiliation" varchar(256)  NULL;
143   affiliations = models.ManyToManyField(Affiliation,related_name='library_affiliations',null=True)
144   # new field Nov/14/08
145   tags = models.ManyToManyField(Tag,related_name='library_tags',blank=True,null=True)
146   # New field Aug/19/08
147   # SQL to add column: alter table fctracker_library add column "replicate" smallint unsigned NULL;
148   REPLICATE_NUM = ((1,1),(2,2),(3,3),(4,4))
149   replicate =  models.PositiveSmallIntegerField(choices=REPLICATE_NUM,default=1) 
150   experiment_type = models.ForeignKey(ExperimentType)
151   library_type = models.ForeignKey(LibraryType, blank=True, null=True)
152   creation_date = models.DateField(blank=True, null=True)
153   made_for = models.CharField(max_length=50, blank=True, 
154       verbose_name='ChIP/DNA/RNA Made By')
155   made_by = models.CharField(max_length=50, blank=True, default="Lorian")
156   
157   PROTOCOL_END_POINTS = (
158       ('?', 'Unknown'),
159       ('Sample', 'Raw sample'),
160       ('Progress', 'In progress'),
161       ('1A', 'Ligation, then gel'),
162       ('PCR', 'Ligation, then PCR'),
163       ('1Ab', 'Ligation, PCR, then gel'),
164       ('1Ac', 'Ligation, gel, then 12x PCR'),
165       ('1Aa', 'Ligation, gel, then 18x PCR'),
166       ('2A', 'Ligation, PCR, gel, PCR'),
167       ('Done', 'Completed'),
168     )
169   stopping_point = models.CharField(max_length=25, choices=PROTOCOL_END_POINTS, default='Done')
170   amplified_from_sample = models.ForeignKey('self', blank=True, null=True, related_name='amplified_into_sample')  
171   
172   undiluted_concentration = models.DecimalField("Concentration", 
173       max_digits=5, decimal_places=2, blank=True, null=True,
174       help_text=u"Undiluted concentration (ng/\u00b5l)") 
175       # note \u00b5 is the micro symbol in unicode
176   successful_pM = models.DecimalField(max_digits=9, decimal_places=1, blank=True, null=True)
177   ten_nM_dilution = models.BooleanField()
178   gel_cut_size = models.IntegerField(default=225, blank=True, null=True)
179   insert_size = models.IntegerField(blank=True, null=True)
180   notes = models.TextField(blank=True)
181
182   bioanalyzer_summary = models.TextField(blank=True,default="")
183   bioanalyzer_concentration = models.DecimalField(max_digits=5, 
184                                 decimal_places=2, blank=True, null=True,
185                                 help_text=u"(ng/\u00b5l)")
186   bioanalyzer_image_url = models.URLField(blank=True,default="")
187   
188   def __unicode__(self):
189     return u'#%s: %s' % (self.id, self.library_name)
190   
191   class Meta:
192     verbose_name_plural = "libraries"
193     #ordering = ["-creation_date"] 
194     ordering = ["-id"]
195   
196   def antibody_name(self):
197     str ='<a target=_self href="/admin/samples/antibody/'+self.antibody.id.__str__()+'/" title="'+self.antibody.__str__()+'">'+self.antibody.nickname+'</a>' 
198     return str
199   antibody_name.allow_tags = True
200
201   def organism(self):
202     return self.library_species.common_name
203
204   def affiliation(self):
205     affs = self.affiliations.all().order_by('name')
206     tstr = ''
207     ar = []
208     for t in affs:
209         ar.append(t.__unicode__())
210     return '%s' % (", ".join(ar))
211     
212   def is_archived(self):
213     """
214     returns True if archived else False
215     """
216     if self.longtermstorage_set.count() > 0:
217         return True
218     else:
219         return False
220
221   def libtags(self):
222     affs = self.tags.all().order_by('tag_name')
223     ar = []
224     for t in affs:
225       ar.append(t.__unicode__())
226     return u'%s' % ( ", ".join(ar))
227
228   def DataRun(self):
229     str ='<a target=_self href="/admin/experiments/datarun/?q='+self.id+'" title="Check All Data Runs for This Specific Library ..." ">Data Run</a>' 
230     return str
231   DataRun.allow_tags = True
232
233   def aligned_m_reads(self):
234     return getLibReads(self.id)
235
236   def aligned_reads(self):
237     res = getLibReads(self.id)
238
239     # Check data sanity
240     if res[2] != "OK":
241       return u'<div style="border:solid red 2px">'+res[2]+'</div>'
242
243     rc = "%1.2f" % (res[1]/1000000.0)
244     # 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
245     if res[0] > 0:
246       bgcolor = '#ff3300'  # Red
247       rc_thr = [10000000,5000000,3000000]
248       if self.experiment_type == 'RNA-seq':
249         rc_thr = [20000000,10000000,6000000]
250
251       if res[1] > rc_thr[0]:
252         bgcolor = '#66ff66'  # Green
253       else:
254         if res[1] > rc_thr[1]:
255           bgcolor ='#00ccff'  # Blue
256         else:
257            if res[1] > rc_thr[2]: 
258              bgcolor ='#ffcc33'  # Orange
259       tstr = '<div style="background-color:'+bgcolor+';color:black">'
260       tstr += res[0].__unicode__()+' Lanes, '+rc+' M Reads'
261       tstr += '</div>'
262     else: tstr = 'not processed yet' 
263     return tstr
264   aligned_reads.allow_tags = True
265   
266   def public(self):
267     SITE_ROOT = '/'
268     summary_url = self.get_absolute_url()
269     return '<a href="%s">S</a>' % (summary_url,)
270   public.allow_tags = True
271     
272   @models.permalink
273   def get_absolute_url(self):
274     return ('htsworkflow.frontend.samples.views.library_to_flowcells', [str(self.id)])
275     
276   
277     
278
279
280 class HTSUser(User):
281     """
282     Provide some site-specific customization for the django user class
283     """
284     #objects = UserManager()
285
286     class Meta:
287         ordering = ['first_name', 'last_name', 'username']
288
289     def admin_url(self):
290         return '/admin/%s/%s/%d' % (self._meta.app_label, self._meta.module_name, self.id)
291
292     def __unicode__(self):
293         #return unicode(self.username) + u" (" + unicode(self.get_full_name()) + u")"
294         return unicode(self.get_full_name()) + u' (' + unicode(self.username) + ')'
295     
296 def HTSUserInsertID(sender, instance, **kwargs):
297     """
298     Force addition of HTSUsers when someone just modifies the auth_user object
299     """
300     u = HTSUser.objects.filter(pk=instance.id)
301     if len(u) == 0:
302         cursor = connection.cursor()
303         cursor.execute('INSERT INTO samples_htsuser (user_ptr_id) VALUES (%s);' % (instance.id,))
304         cursor.close()
305     
306 post_save.connect(HTSUserInsertID, sender=User)