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