Rename avg_lib_size to gel_cut_size, and add insert_size
[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       ('1Aa', 'Ligation, gel, then PCR'),
165       ('2A', 'Ligation, PCR, gel, PCR'),
166       ('Done', 'Completed'),
167     )
168   stopping_point = models.CharField(max_length=25, choices=PROTOCOL_END_POINTS, default='Done')
169   amplified_from_sample = models.ForeignKey('self', blank=True, null=True, related_name='amplified_into_sample')  
170   
171   undiluted_concentration = models.DecimalField("Concentration", 
172       max_digits=5, decimal_places=2, blank=True, null=True,
173       help_text=u"Undiluted concentration (ng/\u00b5l)") 
174       # note \u00b5 is the micro symbol in unicode
175   successful_pM = models.DecimalField(max_digits=9, decimal_places=1, blank=True, null=True)
176   ten_nM_dilution = models.BooleanField()
177   gel_cut_size = models.IntegerField(default=225, blank=True, null=True)
178   insert_size = models.IntegerField(blank=True, null=True)
179   notes = models.TextField(blank=True)
180   
181   def __unicode__(self):
182     return u'#%s: %s' % (self.id, self.library_name)
183   
184   class Meta:
185     verbose_name_plural = "libraries"
186     #ordering = ["-creation_date"] 
187     ordering = ["-id"]
188   
189   def antibody_name(self):
190     str ='<a target=_self href="/admin/samples/antibody/'+self.antibody.id.__str__()+'/" title="'+self.antibody.__str__()+'">'+self.antibody.nickname+'</a>' 
191     return str
192   antibody_name.allow_tags = True
193
194   def organism(self):
195     return self.library_species.common_name
196
197   def affiliation(self):
198     affs = self.affiliations.all().order_by('name')
199     tstr = ''
200     ar = []
201     for t in affs:
202         ar.append(t.__unicode__())
203     return '%s' % (", ".join(ar))
204     
205   def is_archived(self):
206     """
207     returns True if archived else False
208     """
209     if self.longtermstorage_set.count() > 0:
210         return True
211     else:
212         return False
213
214   def libtags(self):
215     affs = self.tags.all().order_by('tag_name')
216     ar = []
217     for t in affs:
218       ar.append(t.__unicode__())
219     return u'%s' % ( ", ".join(ar))
220
221   def DataRun(self):
222     str ='<a target=_self href="/admin/experiments/datarun/?q='+self.id+'" title="Check All Data Runs for This Specific Library ..." ">Data Run</a>' 
223     return str
224   DataRun.allow_tags = True
225
226   def aligned_m_reads(self):
227     return getLibReads(self.id)
228
229   def aligned_reads(self):
230     res = getLibReads(self.id)
231
232     # Check data sanity
233     if res[2] != "OK":
234       return u'<div style="border:solid red 2px">'+res[2]+'</div>'
235
236     rc = "%1.2f" % (res[1]/1000000.0)
237     # 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
238     if res[0] > 0:
239       bgcolor = '#ff3300'  # Red
240       rc_thr = [10000000,5000000,3000000]
241       if self.experiment_type == 'RNA-seq':
242         rc_thr = [20000000,10000000,6000000]
243
244       if res[1] > rc_thr[0]:
245         bgcolor = '#66ff66'  # Green
246       else:
247         if res[1] > rc_thr[1]:
248           bgcolor ='#00ccff'  # Blue
249         else:
250            if res[1] > rc_thr[2]: 
251              bgcolor ='#ffcc33'  # Orange
252       tstr = '<div style="background-color:'+bgcolor+';color:black">'
253       tstr += res[0].__unicode__()+' Lanes, '+rc+' M Reads'
254       tstr += '</div>'
255     else: tstr = 'not processed yet' 
256     return tstr
257   aligned_reads.allow_tags = True
258   
259   def public(self):
260     SITE_ROOT = '/'
261     summary_url = self.get_absolute_url()
262     return '<a href="%s">S</a>' % (summary_url,)
263   public.allow_tags = True
264     
265   @models.permalink
266   def get_absolute_url(self):
267     return ('htsworkflow.frontend.samples.views.library_to_flowcells', [str(self.id)])
268     
269   
270     
271
272
273 class HTSUser(User):
274     """
275     Provide some site-specific customization for the django user class
276     """
277     #objects = UserManager()
278
279     class Meta:
280         ordering = ['first_name', 'last_name', 'username']
281
282     def admin_url(self):
283         return '/admin/%s/%s/%d' % (self._meta.app_label, self._meta.module_name, self.id)
284
285     def __unicode__(self):
286         #return unicode(self.username) + u" (" + unicode(self.get_full_name()) + u")"
287         return unicode(self.get_full_name()) + u' (' + unicode(self.username) + ')'
288     
289 def HTSUserInsertID(sender, instance, **kwargs):
290     """
291     Force addition of HTSUsers when someone just modifies the auth_user object
292     """
293     u = HTSUser.objects.filter(pk=instance.id)
294     if len(u) == 0:
295         cursor = connection.cursor()
296         cursor.execute('INSERT INTO samples_htsuser (user_ptr_id) VALUES (%s);' % (instance.id,))
297         cursor.close()
298     
299 post_save.connect(HTSUserInsertID, sender=User)